#ifndef __WIN_PE_IMPL__
#define __WIN_PE_IMPL__

#include <Windows.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <search.h>
#include <assert.h>

#include <string>
#include <memory>
#include <vector>
#include <map>
#include <list>

#include "../../../interface/iarchpe.h"
#include "utility.hpp"
#include "pdbinfo.hpp"

#pragma warning(push)
#pragma warning(disable: 4996)

#define RFAILEDB(x)		{ if( FAILED((x)) ) return FALSE; }
#define RFAILEDZ(x)		{ if( FAILED((x)) ) return 0; }

namespace xm
{
//////////////////////////////////////////////////////////////////////////
#define IMAGE_REL_OFFSET(W)\
	(TU16)((TU16)(W)&0xFFF)

#define IMAGE_REL_TYPE(W)\
	(TU16)((TU16)(W)&0xF000 >> 12)

#define DATA_CLEAN(DAT)\
	memset(&(DAT), 0, sizeof((DAT)))

#define CONT_CLEAN(CNT)\
	CNT.clear()

#define DEFMETHOD(TRET, TNAME)\
	virtual __stdcall TRET TNAME

//////////////////////////////////////////////////////////////////////////
#define RSRC_ID_FLAGE\
	(0x80000000U)

#define RSRC_ID(id)\
	((LPCSTR)(RSRC_ID_FLAGE | (xm::TU32)(id)))

#define RSRC_ID_VAL(sz)\
	((xm::TU16)(((xm::TU32)sz) & 0xFFFF))

#define RSRC_IS_ID(nm)\
	((RSRC_ID_FLAGE & (xm::TU32)(nm)) != 0)

//#define RVSURE(x,y)			{ if( !(x) ) return (y); }
//#define RBSURE(x)			{ if(!(x)) return FALSE; }
//#define ADDR_ASSIGN(x,y)	(*(x) = (y))
//////////////////////////////////////////////////////////////////////////
class WinPeHeaderX32
{
public:
	//////////////////////////////////////////////////////////////////////////
	typedef TU32							TImgRaw;
	typedef TU32							TImgRva;
	typedef TU32							TImgVa;
	typedef TU32							TImgSize;
	typedef TU32							TImgTms;

	//////////////////////////////////////////////////////////////////////////
	typedef IMAGE_DOS_HEADER				TImgDosHdr;
	typedef IMAGE_FILE_HEADER				TImgFileHdr;
	typedef IMAGE_NT_HEADERS32				TImgNtHdr;
	typedef IMAGE_OPTIONAL_HEADER32			TImgOptHdr;
	typedef	IMAGE_SECTION_HEADER			TImgSecHdr;
	typedef IMAGE_DATA_DIRECTORY			TImgDatDir;

	typedef IMAGE_THUNK_DATA32				TImgThkDat;

	typedef IMAGE_IMPORT_DESCRIPTOR			TImgImpDes;
	typedef IMAGE_EXPORT_DIRECTORY			TImgExpDir;
	typedef IMAGE_RESOURCE_DIRECTORY		TImgResDir;
	typedef IMAGE_TLS_DIRECTORY32			TImgTlsDir;	
	typedef IMAGE_DEBUG_DIRECTORY			TImgDbgDir;
	typedef IMAGE_LOAD_CONFIG_DIRECTORY32	TImgCfgDir;
	typedef IMAGE_DELAY_IMPORT_DESCRIPTOR	TImgDlyDes;
	typedef WIN_CERTIFICATE					TImgCrtDir;
	typedef IMAGE_BOUND_IMPORT_DESCRIPTOR	TImgBndDes;
	typedef IMAGE_BOUND_FORWARDER_REF		TImgBndFwd;
	typedef IMAGE_COR20_HEADER				TImgClrDir;

	typedef IMAGE_RESOURCE_DIRECTORY_ENTRY	TImgResEnt;
	typedef IMAGE_RESOURCE_DATA_ENTRY		TImgResDat;
	typedef IMAGE_BASE_RELOCATION			TImgBasRel;


	//////////////////////////////////////////////////////////////////////////
};

class WinPeHeaderX64
{
public:
	//////////////////////////////////////////////////////////////////////////
	typedef TU32							TImgRaw;
	typedef TU32							TImgRva;
	typedef TU64							TImgVa;
	typedef TU32							TImgSize;
	typedef TU32							TImgTms;

	//////////////////////////////////////////////////////////////////////////
	typedef IMAGE_DOS_HEADER				TImgDosHdr;
	typedef IMAGE_FILE_HEADER				TImgFileHdr;
	typedef IMAGE_NT_HEADERS64				TImgNtHdr;
	typedef IMAGE_OPTIONAL_HEADER64			TImgOptHdr;
	typedef	IMAGE_SECTION_HEADER			TImgSecHdr;
	typedef IMAGE_DATA_DIRECTORY			TImgDatDir;

	typedef IMAGE_THUNK_DATA64				TImgThkDat;

	typedef IMAGE_IMPORT_DESCRIPTOR			TImgImpDes;
	typedef IMAGE_EXPORT_DIRECTORY			TImgExpDir;
	typedef IMAGE_RESOURCE_DIRECTORY		TImgResDir;
	typedef IMAGE_TLS_DIRECTORY64			TImgTlsDir;	
	typedef IMAGE_DEBUG_DIRECTORY			TImgDbgDir;
	typedef IMAGE_LOAD_CONFIG_DIRECTORY64	TImgCfgDir;
	typedef IMAGE_DELAY_IMPORT_DESCRIPTOR	TImgDlyDes;
	typedef WIN_CERTIFICATE					TImgCrtDir;
	typedef IMAGE_BOUND_IMPORT_DESCRIPTOR	TImgBndDes;
	typedef IMAGE_BOUND_FORWARDER_REF		TImgBndFwd;
	typedef IMAGE_COR20_HEADER				TImgClrDir;

	typedef IMAGE_RESOURCE_DIRECTORY_ENTRY	TImgResEnt;
	typedef IMAGE_RESOURCE_DATA_ENTRY		TImgResDat;
	typedef IMAGE_BASE_RELOCATION			TImgBasRel;
};


//////////////////////////////////////////////////////////////////////////
typedef enum 
{
	WINPE_DOS_HEADER,
	WINPE_NT_HEADERS,
	WINPE_OPTIONAL_HEADER,
	WINPE_FILE_HEADER,
	WINPE_DATA_DIRECTORY,
	WINPE_SECTION_HEADER,
	WINPE_EXPORT_DIRECTORY,
	WINPE_IMPORT_DIRECTORY,
	WINPE_CERTIFICATE_DIRECTORY,
	WINPE_DEBUG_DIRECTORY,
	WINPE_TLS_DIRECTORY,
	WINPE_LOAD_CONFIG_DIRECTORY,
	WINPE_BOUND_IMPORT_DESCRIPTOR,
	WINPE_CLR_RUNTIME_DIRECTORY,
	WINPE_DELAY_IMPORT_DESCRIPTOR,
}WINPE_IMAGE_HEADER_TYPE;
//////////////////////////////////////////////////////////////////////////

class WinPeParser: public IPeReader, UnkBase
{
public:
	UNKNOWN_IMP2(IKArchive,IPeReader);

	HRESULT init_class( IUnknown * xt, IUnknown * ob )
	{
		return S_OK;
	}

public:	
	//////////////////////////////////////////////////////////////////////////
	typedef TU32									TImgRaw;
	typedef TU32									TImgRva;
	typedef TU64									TImgVa;
	typedef TU32									TImgSize;
	typedef TU32									TImgTms;

	//////////////////////////////////////////////////////////////////////////
	typedef std::string								TString;
	typedef IKFileStream								TStream;
	typedef	WinPeParser							TThis;

protected:	
	//////////////////////////////////////////////////////////////////////////
	enum
	{
		WINPE_MAX_SECTION_COUNT						= 64,
		WINPE_MAX_IMPORT_COUNT						= 64,
		WINPE_MAX_STRING_LENGTH						= 256,
		WINPE_MAX_FUNCTION_COUNT					= 256,
		WINPE_MAX_RESOURCE_NAME_CCH					= 260,
		WINPE_MAX_RESOURCE_ENTRY_COUNT				= 64,
		WINPE_MAX_RESOURCE_DEEP_LEVEL				= 3,
		WINPE_MAX_RESOURCE_DATA_SIZE				= 8*1024*1024,
		WINPE_MAX_RELOCATION_BLOCK_SIZE 			= 8*1024,
		WINPE_MAX_TLS_CALLBACK_COUNT				= 0x400,
		WINPE_MAX_FILE_BLOCK_SIZE       			= 0x80000000,
		WINPE_RELOCATION_PAGE_SIZE					= 4*1024,
	};
	//////////////////////////////////////////////////////////////////////////
	typedef std::vector<TString>					TStrVtr;
	typedef std::vector<TU64>						TU64Vtr;
	typedef std::vector<TU32>						TU32Vtr;
	typedef std::vector<TU16>						TU16Vtr;
	typedef std::vector<TU08>						TU08Vtr;

protected:		
	//////////////////////////////////////////////////////////////////////////
	xm::iptr<IKFileStream>		m_lpStream;

	//////////////////////////////////////////////////////////////////////////
	TU32					m_dwTouchLevel;
	TU32					m_dwParseResult;
	BOOL					m_bWow64Flage;

	typedef BOOL(TThis::*TParsePtr)();
	typedef VOID(TThis::*TClearPtr)();
	typedef struct _ParseItem
	{
		TU32		dwLevMask;		
		TParsePtr	fnParser;
		TClearPtr	fnClear;
		TU32		dwLevDepend;		
	}TParseItem;

	//////////////////////////////////////////////////////////////////////////
	TU64					m_dwFileSize;

	//////////////////////////////////////////////////////////////////////////
	TImgDosHdr				m_aImgMzHdr;
	TImgNtHdrBnd			m_aImgNtHdr;

	TImgRva					m_dwEntryPoint;
	TImgRaw					m_dwFileAlign;
	TImgRva					m_dwSectAlign;

	//////////////////////////////////////////////////////////////////////////
	typedef std::vector<IMAGE_SECTION_HEADER>  TImgSecHdrVtr;
	TImgSecHdrVtr			m_aImgSecHdrLst;
	TStrVtr					m_aImgSecNameLst;

	typedef struct _SecMapItem
	{
		TU32	dwSecIdx;
		TImgRva dwBegRva;
		TImgRva dwEndRva;
		TImgRaw dwBegRaw;
		TImgRaw dwEndRaw;
	}TSecMapItem;
	typedef std::vector<TSecMapItem> TSecMapList;
	TSecMapList				m_aSecMapList;
	TU32					m_dwMaxSectRva;
	TU32					m_dwMaxSectRaw;

	//////////////////////////////////////////////////////////////////////////
	typedef struct _FuncEnt
	{
		TU32	TU32inal;
		TImgRva	dwAddrRva;
		TU32	nameRVA;
	}	TFuncEnt;
	typedef std::map<TString, TFuncEnt> TFuncMap;
	typedef std::map<TString, TFuncMap> TModuleMap;	

	//////////////////////////////////////////////////////////////////////////
	// 01. Export Data Directory
	TString					m_sExportModule;
	TFuncMap				m_aExportMap;

	// 02. Import Data Directory
	TImgExpDir				m_aImgExpDir;	
	typedef std::map<TString, TImgImpDes> TImgImpMap;
	TImgImpMap				m_aImgImpMap;
	TModuleMap				m_aImportMap;

	// 03. Resource Data Directory
#pragma pack(push, 2)
	class TWinResDat
	{
	public:
		typedef TImgResDat	THeader;

	public:
		THeader		aHeader;
		TImgRva		DatRva;
		TImgSize	DatLen;

		inline THeader* Header()
		{
			return &aHeader;
		}
	};
#pragma pack(pop)

#pragma pack(push, 2)
	class TWinResLst;
	class TWinResEnt
	{
		enum
		{
			RSE_NAME_IS_ID		= 0x00000001,
			RSE_CHILD_IS_DATA	= 0x00010000,
		};

		typedef TWinResEnt	TThis;
		typedef TWinResDat	TData;
		typedef TWinResLst	TList;

		//////////////////////////////////////////////////////////////////////////
		TU32	dwAttrib;
	public:
		union
		{
			LPCSTR	szName;
			TU16	nId;
		};
		union
		{
			TList*	lpList;
			TData*	lpData;
		};

		//////////////////////////////////////////////////////////////////////////
	public:
		TWinResEnt()
		{
			dwAttrib	= 0;
			szName		= NULL;
			lpData		= NULL;
		}

		~TWinResEnt()
		{
			Clear();
		}
	public:
		VOID inline SetNameId(TU16 nId)
		{
			dwAttrib |= RSE_NAME_IS_ID;
			szName = (LPCSTR)nId;
		}

		VOID inline SetNameStr(LPCSTR lpName)
		{
			dwAttrib &= (~RSE_NAME_IS_ID);
			szName = lpName;
		}

		BOOL inline IsNameId()
		{
			return (dwAttrib & RSE_NAME_IS_ID) > 0? TRUE: FALSE;
		}

		LPCSTR inline NameId()
		{
			if(IsNameId())
				return RSRC_ID(nId);
			else
				return szName;
		}
		BOOL inline IsSubData()
		{
			return (dwAttrib & RSE_CHILD_IS_DATA) > 0? TRUE: FALSE;
		}

		BOOL inline IsSubList()
		{
			return !IsSubData();
		}

		VOID inline SetSubList(TList* lpList)
		{
			dwAttrib &= (~RSE_CHILD_IS_DATA);
			this->lpList = lpList;
		}

		VOID inline SetSubData(TData* lpData)
		{
			dwAttrib |= RSE_CHILD_IS_DATA;	
			this->lpData = lpData;
		}

		inline TData* SubData()
		{
			if(!IsSubData())
				return NULL;
			return lpData;
		}

		inline TList* SubList()
		{
			if(!IsSubList())
				return NULL;
			return lpList;
		}
		inline VOID SetNull()
		{
			dwAttrib = 0;
			szName = NULL;
			lpData = NULL;
		}

		inline BOOL IsNull()
		{
			return (!szName && !dwAttrib)?TRUE: FALSE;
		}	

		inline TThis* SubFind(LPCSTR szName)
		{
			if(!szName)
				return NULL;

			if(!IsSubList())
				return NULL;

			if(!lpList)
				return NULL;

			TThis* lpRetEnt = lpList->Find(szName);
			return lpRetEnt;
		}

		inline LPCSTR SubNext(LPCSTR szName)
		{
			if(!IsSubList())
				return NULL;

			if(!lpList)
				return NULL;

			return lpList->Next(szName);;
		}

		inline VOID Clear()
		{
			szName = NULL;
			if(IsSubData())
			{
				delete lpData;
				lpData = NULL;
			}
			else
			{
				delete lpList;
				lpList = NULL;
			}
		}
	};
#pragma pack(pop)

#pragma pack(push, 4)
	class TWinResLst
	{
		//////////////////////////////////////////////////////////////////////////
	public:
		typedef TWinResLst TThis;
		typedef TImgResDir THeader;
		typedef	TWinResEnt TEntry;

		//////////////////////////////////////////////////////////////////////////
	protected:
		THeader				aHeader;	
		TU16				nEntryCnt;
		TU16				nIdCnt;
		TU16				nNameCnt;	
		//TImgResEnt		Entries;

		//////////////////////////////////////////////////////////////////////////
	protected:
		TWinResLst()
		{
			memset(&aHeader, 0, sizeof(aHeader));
			nEntryCnt	= 0;
			nIdCnt		= 0;
			nNameCnt	= 0;			
		}

	public:
		~TWinResLst()
		{
			Clear();
		}

		//////////////////////////////////////////////////////////////////////////
	protected:
		static int __cdecl AllCmp(TEntry* lpLtEnt, TEntry* lpRtEnt)
		{
			BOOL bLtNull = lpLtEnt->IsNull();
			BOOL bRtNull = lpRtEnt->IsNull();
			if(bLtNull || bRtNull)
			{
				if(bLtNull)
					return 1;
				else if(bRtNull)
					return -1;
				else
					return 0;
			}

			BOOL bLtId = lpLtEnt->IsNameId();
			BOOL bRtId = lpRtEnt->IsNameId();
			if(bLtId && bRtId)
			{
				return IdCmp(lpLtEnt, lpRtEnt);
			}
			else if(!bLtId && !bRtId)
			{
				return NameCmp(lpLtEnt, lpRtEnt);
			}
			else
			{
				if(bLtId)
					return -1;
				else
					return 1;
			}
		}
		static int __cdecl IdCmp(const TEntry* lpLtEnt, const TEntry* lpRtEnt)
		{
			WORD wLftId = lpLtEnt->nId; 
			WORD wRgtId = lpRtEnt->nId; 

			if(wLftId == wRgtId)
				return 0;
			else if(wLftId < wRgtId)
				return -1;
			else
				return 1;
		}

		static int __cdecl NameCmp(const TEntry* lpLtEnt, const TEntry* lpRtEnt)
		{
			LPCSTR lpLtStr = lpLtEnt->szName;
			LPCSTR lpRtStr = lpRtEnt->szName;
			return strcmp(lpLtStr, lpRtStr);
		}
		typedef int  (__cdecl*TEntCmpPtr)(const void* lpLtEnt, const void* lpRtEnt);

	public:
		inline THeader* Header()
		{
			return &aHeader;
		}

		inline TEntry* Entry(TU32 nIndex = 0)
		{
			if(nIndex > nEntryCnt)
				return NULL;

			TEntry* lpEntries = (TEntry*)&((TU08*)this)[sizeof(TThis)];
			return &lpEntries[nIndex];
		}

		TU32 Count()
		{
			return nIdCnt + nNameCnt;
		}

		TEntry* Find(LPCSTR szName)
		{		
			if(RSRC_IS_ID(szName))
			{	
				TEntry aKeyEnt;
				aKeyEnt.SetNameId((TU16)szName);

				TEntry* lpEntLst = Entry(0);
				TEntry* lpTarEnt = (TEntry*)bsearch(&aKeyEnt, lpEntLst, nIdCnt, sizeof(TEntry), (TEntCmpPtr)IdCmp);
				if(!lpTarEnt)
					return NULL;

				return lpTarEnt;
			}
			else
			{
				TEntry aKeyEnt;
				aKeyEnt.SetNameStr(szName);

				TEntry* lpEntLst = Entry(nIdCnt);
				TEntry* lpTarEnt = (TEntry*)bsearch(&aKeyEnt, lpEntLst, nNameCnt, sizeof(TEntry), (TEntCmpPtr)NameCmp);
				if(!lpTarEnt)
					return NULL;

				return lpTarEnt;
			}
		}

		LPCSTR Next(LPCSTR szName)
		{
			if(!szName)
			{	
				if(!Count())
					return NULL;

				TEntry* lpNext = Entry(0);
				return lpNext->NameId();
			}
			else
			{
				TEntry* lpEntry = Find(szName);
				if(!lpEntry)
					return NULL;

				TEntry* lpEntLst = Entry(0);
				TU32 nEntCnt = Count();
				TU32 nIndex = lpEntry-lpEntLst;

				LPCSTR lpRetNxt = NULL;
				do
				{
					if(nIndex >= nEntCnt)
						return NULL;

					nIndex++;
					TEntry* lpNext = Entry(nIndex);
					if(!lpNext)
						return NULL;

					lpRetNxt = lpNext->NameId();
				}while(lpRetNxt == szName);			
				return lpRetNxt;
			}			
		}

		BOOL Rebuild(TU32 nId, TU32 nName)
		{
			if((nId + nName) == 0)
				return FALSE;

			nIdCnt = (TU16)nId;
			nNameCnt = (TU16)nName;

			TEntry* lpEntLst = Entry(0);
			qsort(lpEntLst, nIdCnt + nNameCnt, sizeof(TEntry), (TEntCmpPtr)AllCmp);
			return TRUE;
		}	

		VOID Clear()
		{
			for(TU32 n = 0; n < nEntryCnt; n++)
				Entry(n)->Clear();

			memset(&aHeader, 0, sizeof(THeader));
			nEntryCnt	= 0;
			nIdCnt		= 0;
			nNameCnt	= 0;
		}

		static TThis* Alloc(TU32 nCount)
		{
			TU32 nSize = sizeof(TThis) + nCount*sizeof(TEntry);
			TU08* lpBuff = new TU08[nSize];
			if(!lpBuff)
				return NULL;

			memset(lpBuff, 0, nSize);
			TThis* lpNewObj = (TThis*)lpBuff;
			lpNewObj->nEntryCnt = (TU16)nCount;
			return lpNewObj;
		}

		static VOID Free(TThis* lpThis)
		{
			if(!lpThis)
				return;

			lpThis->Clear();
			delete lpThis;
		}
	};
#pragma pack(pop)
	typedef std::auto_ptr<TWinResEnt>			TRsrcEntPtr;
	typedef std::auto_ptr<TWinResLst>			TRsrcLstPtr;
	typedef std::list<TString>					TStrLst;
	TStrLst					m_aRsrcNameLst;
	TWinResEnt				m_aRsrcRootEnt;
	TU32					m_dwRrscDataCnt;

	// 04. Exception Table

	// 05. Certificate Table
	WIN_CERTIFICATE			m_aWinCertHdr;
	TImgRaw					m_dwCertRaw;
	TU32					m_dwCertLen;	

	// 06. Base Relocation Table
	typedef std::vector<TU16>					TRelocBlock;
	typedef std::map<TImgRva, TRelocBlock>		TRelocMap;
	TRelocMap				m_aRelocMap;

	// 07. Debug Data Directory
	TImgDbgDir				m_aImgDbgDir;
	TString					m_sDebugFilePath;

	// 08. Architecture (Reserved)

	// 09. Global Ptr (Reserved)

	// 10. TLS Table
	TImgTlsDirBnd			m_aImgTlsDir;
	typedef std::vector<TImgRva>				TTlsCallBackVtr;
	TTlsCallBackVtr			m_aTlsFuncLst;	

	// 11. Load Config Table
	TImgCfgDirBnd			m_aImgCfgDir;
	typedef std::vector<TImgRva>				TSehHandlerVtr;
	TSehHandlerVtr			m_aImgSehHdlLst;

	// 12. Bound Import Table
	typedef std::vector<TImgBndDes>				TImgBndDesVtr;
	typedef std::map<TString, TImgBndDes*>		TImgBndModMap;
	typedef	std::map<TU16, TString>				TImgBndNameMap;
	TImgBndDesVtr			m_aImgBndDesLst;
	TImgBndModMap			m_aBndModNameMap;
	TImgBndNameMap			m_aBndFwdNameMap;

	// 13. Import Address Table

	// 14. Delay Import Descriptor
	typedef std::map<TString, TImgDlyDes>		TImgDlyDesMap;
	TImgDlyDesMap			m_aImgDlyMap;
	TModuleMap				m_aDlyFucMap;

	// 15. Clr Runtime
	TImgClrDir				m_aImgClrHdr;
					
public:
	WinPeParser()
		: m_lpStream(0)
		, m_dwTouchLevel(0)
		, m_dwParseResult(0)
	{
	
	}

	~WinPeParser()
	{
		Close();
	}

public:
	BOOL Result(TU32 dwLevel)
	{
		if(dwLevel)
			RBSURE((m_dwParseResult & dwLevel) == dwLevel);
		return TRUE;
	}

	BOOL Touch(TU32 dwLevel)
	{
		if(dwLevel)
			RBSURE((m_dwTouchLevel & dwLevel) == dwLevel);
		return TRUE;
	}

	STDMETHOD(GetFormat)(FMTID * lpFormat )
	{
		if( !lpFormat ) return E_INVALIDARG;
		*lpFormat = FMT_PE;
		return S_OK;
	}

	STDMETHOD(Open)(IUnknown* lpStream, FMTID fmt, SIZE_T dwLevel = PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS)
	{
		Close();

		if( fmt != FMT_PE ) 
			return E_UNEXPECTED;

		m_lpStream = lpStream;

		if( !m_lpStream ) 
			return E_NOINTERFACE;

		if(!Parse(dwLevel))
			return E_FAIL;

		return S_OK;
	}
	STDMETHOD(GetStream)( IKFileStream** pstm )
	{
		if( !pstm ) return E_INVALIDARG;
		if( !m_lpStream ) return E_UNEXPECTED;
		*pstm = m_lpStream;
		m_lpStream->AddRef();
		return S_OK;
	}
	STDMETHOD(ReOpen)( SIZE_T dwLevel = PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS )
	{
		return Open( m_lpStream, dwLevel );
	}
															
	STDMETHOD(Close)()
	{
		Clear();
		m_lpStream = NULL;
		return S_OK;
	}
							
	virtual TStream* Stream()
	{
		return m_lpStream;
	}

	virtual BOOL IsWow64(){ return m_bWow64Flage;}
public:
	//////////////////////////////////////////////////////////////////////////
	virtual BOOL IsValidRaw(TImgRaw dwRaw, TImgSize dwSize = 1)
	{
		RBSURE(dwSize > 0 && dwSize < WINPE_MAX_FILE_BLOCK_SIZE);

		TU64 dwFileSize = 0;
		RBSURE(FileSize(&dwFileSize));
		RBSURE(dwFileSize > 0);

		TImgRaw dwEndRaw = dwRaw + dwSize;
		RBSURE(dwEndRaw <= dwFileSize);
		return TRUE;
	}
	virtual BOOL IsValidRva(TImgRva dwRva, TImgSize dwSize = 1)
	{
		TImgRaw dwBegRaw = 0;
		RBSURE(Rva2Raw(dwRva, dwSize, &dwBegRaw));
		RBSURE(IsValidRaw(dwBegRaw, dwSize));
		return TRUE;
	}

	virtual BOOL IsValidVa(TU64 dwVa, TImgSize dwSize = 1)
	{
		TImgRva dwBegRva = 0;
		RBSURE(Va2Rva(dwVa, dwSize, &dwBegRva));
		RBSURE(IsValidRva(dwBegRva, dwSize));
		return TRUE; 
	}

	virtual BOOL Va2Rva(TU64 dwVa, TImgSize dwSize = 1, TImgRva* lpRva = NULL)
	{	
		RBSURE(dwVa > 0);
		RBSURE(dwSize < WINPE_MAX_FILE_BLOCK_SIZE);

		TU64 dwImgBase = 0; TU32 dwImgSize = 0;
		RBSURE(ImageBaseVa(&dwImgBase, &dwImgSize));
		RBSURE(dwImgBase > 0 && dwImgSize > 0);
		RBSURE(dwVa >=  dwImgBase);	
	
		TU64 dwImgEnd = dwImgBase + dwImgSize;
		RBSURE(dwImgEnd != dwImgBase);

		TU64 dwTarEnd = dwVa + dwSize;
		RBSURE(dwTarEnd <= dwImgEnd);

		ADDR_ASSIGN(lpRva, (TImgRva)(dwVa - dwImgBase));
		return TRUE;		
	}

	virtual BOOL Rva2Va(TImgRva dwRva, TImgSize dwSize = 1, TU64* lpVa = NULL)
	{
		RBSURE(dwSize < WINPE_MAX_FILE_BLOCK_SIZE);

		TU64 dwImgBaseVa = 0; TU32 dwImgSize = 0;
		RBSURE(ImageBaseVa(&dwImgBaseVa, &dwImgSize));

		TU64 dwImgEnd = dwImgBaseVa + dwImgSize;
		RBSURE(dwImgEnd != dwImgBaseVa);

		TU64 dwVa = 0, dwTarEndVa = 0;
		dwVa = dwImgBaseVa + dwRva;
		dwTarEndVa = dwVa + dwSize;
		RBSURE(dwTarEndVa <= dwImgEnd);		
		ADDR_ASSIGN(lpVa, dwVa);
		return TRUE;
	}

	virtual BOOL Rva2Raw(TImgRva dwRva, TImgSize dwSize = 1, TImgRaw* lpRaw = NULL, TU32* lpSec = NULL)
	{
		RBSURE(dwSize < WINPE_MAX_FILE_BLOCK_SIZE);

		TU32 nSecIdx = 0;
		TImgRva dwRvaEnd = dwRva + dwSize;
		for(TSecMapList::iterator\
			sitr = m_aSecMapList.begin();
			sitr != m_aSecMapList.end();
			sitr ++, nSecIdx++)
			{
				TSecMapItem& rMapItm = *sitr;

				if(dwRva < rMapItm.dwBegRva)
					continue;

				if(dwRva >= rMapItm.dwEndRva)
					continue;

				TImgRaw dwRetBegRaw = rMapItm.dwBegRaw + dwRva - rMapItm.dwBegRva;
				TImgRaw dwRetEndRaw = dwRetBegRaw + dwSize;
				
				if(lpRaw)
					*lpRaw = dwRetBegRaw;

				if(lpSec)
					*lpSec = rMapItm.dwSecIdx;

				return TRUE;
			}

		return FALSE;
	}

	virtual BOOL Raw2Rva(TImgRaw dwRaw, TImgSize dwSize = 1, TImgRva* lpRva = NULL, TU32* lpSec = NULL)
	{
		RBSURE(dwSize < WINPE_MAX_FILE_BLOCK_SIZE);

		TU32 nSecIdx = 0;
		TImgRaw dwRawEnd = dwRaw + dwSize;
		for(TSecMapList::iterator\
			sitr = m_aSecMapList.begin();
			sitr != m_aSecMapList.end();
		sitr ++, nSecIdx++)
		{
			TSecMapItem& rMapItm = *sitr;

			if(dwRaw < rMapItm.dwBegRaw)
				continue;

			if(dwRawEnd > rMapItm.dwEndRaw)
				continue;

			TImgRva dwRetBegRva = rMapItm.dwBegRva + dwRaw - rMapItm.dwBegRaw;
			TImgRva dwRetEndRva = dwRetBegRva + dwSize;

			if(lpRva)
				*lpRva = dwRetBegRva;

			if(lpSec)
				*lpSec = rMapItm.dwSecIdx;

			return TRUE;
		}

		return FALSE;
	}	
	virtual BOOL ReadDatRaw(TImgRaw dwRaw, LPVOID lpBuff, TImgSize dwLen)
	{
		RBSURE(m_lpStream);
		RBSURE(lpBuff && dwLen);
		RFAILEDB(m_lpStream->SetPos((TU64)dwRaw));
		SIZE_T dwDone = 0;
		RFAILEDB(m_lpStream->Read(lpBuff, dwLen, &dwDone));
		RBSURE(dwDone == dwLen);
		return TRUE;
	}
	virtual DWORD ReadDatRaw2(DWORD dwRaw, LPVOID lpBuff, DWORD dwLen)
	{
		if( !m_lpStream ) return 0;
		if( !lpBuff || !dwLen ) return 0;
		if( FAILED(m_lpStream->SetPos((TU64)dwRaw)) )
			return 0;
		SIZE_T dwDone = 0;
		RFAILEDZ(m_lpStream->Read(lpBuff, dwLen, &dwDone));
		return dwDone;
	}

	virtual BOOL ReadDatRva(TImgRva dwRva, LPVOID lpBuff, TImgSize dwLen)
	{
		TImgRaw dwRaw = 0;
		RBSURE(Rva2Raw(dwRva, dwLen, &dwRaw));
		RBSURE(ReadDatRaw(dwRaw, lpBuff, dwLen));
		return TRUE;
	}
	virtual DWORD ReadDatRva2(DWORD dwRva, LPVOID lpBuff, DWORD dwLen)
	{
		TImgRaw dwRaw = 0;
		if(!Rva2Raw(dwRva, dwLen, &dwRaw)) return 0;
		return ReadDatRaw2(dwRaw, lpBuff, dwLen );
	}

	virtual BOOL ReadDatVa(TU64 dwVa, LPVOID lpBuff, TImgSize dwLen)
	{
		TImgRva dwRva = 0;
		RBSURE(Va2Rva(dwVa, dwLen, &dwRva));
		RBSURE(ReadDatRva(dwRva, lpBuff, dwLen));
		return TRUE;
	}


protected:
	BOOL ReadStrRvaA(TImgRva dwRva, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		TImgRaw dwStrRaw = 0;
		RBSURE(Rva2Raw(dwRva, 1, &dwStrRaw));
		RBSURE(ReadStrRawA(dwStrRaw, rOutStr, dwMaxLen));
		return TRUE;
	}

	BOOL ReadStrRvaU(TImgRva dwRva, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		TImgRaw dwStrRaw = 0;
		RBSURE(Rva2Raw(dwRva, 1, &dwStrRaw));
		RBSURE(ReadStrRawU(dwStrRaw, rOutStr, dwMaxLen));
		return TRUE;
	}

	BOOL ReadStrRawA(TImgRaw dwRaw, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		TU32 dwBuffLen = dwMaxLen * sizeof(CHAR);
		CHAR* szTmpBuff = (CHAR*)alloca(dwBuffLen);

		TStream* lpStream = Stream();
		RBSURE(lpStream);
		RFAILEDB(lpStream->SetPos(dwRaw));

		SIZE_T dwDoneCnt = 0;
		RFAILEDB(lpStream->Read(szTmpBuff, dwBuffLen, &dwDoneCnt));
		RBSURE(dwDoneCnt);

		SIZE_T dwStrLen = strnlen(szTmpBuff, dwDoneCnt);
		RBSURE(dwStrLen);

		rOutStr = szTmpBuff;
		return TRUE;
	}

	BOOL ReadStrRawU(TU32 dwRaw, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		TU32 dwBuffLen = dwMaxLen * sizeof(WCHAR);
		WCHAR* szTmpBuff = (WCHAR*)alloca(dwBuffLen);
		RBSURE(Stream());
		RBSURE(Stream()->SetPos(dwRaw));

		SIZE_T qwDone;
		RBSURE(Stream()->Read(szTmpBuff, dwBuffLen, &qwDone));

		TU32 dwDoneCnt = (TU32)qwDone / sizeof(WCHAR);
		RBSURE(dwDoneCnt);

		CHAR* szTmpAnsi = (CHAR*)alloca(dwBuffLen);
		RBSURE(wcstombs(szTmpAnsi, szTmpBuff, dwBuffLen));

		rOutStr = szTmpAnsi;
		return TRUE;
	}

	BOOL ReadRsrcStrRvaA(TImgRva dwRva, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		TImgRaw dwStrRaw = 0;
		RBSURE(Rva2Raw(dwRva, 1, &dwStrRaw));
		RBSURE(ReadRsrcStrRawA(dwStrRaw, rOutStr, dwMaxLen));
		return TRUE;
	}

	BOOL ReadRsrcStrRvaU(TImgRva dwRva, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		TImgRaw dwStrRaw = 0;
		RBSURE(Rva2Raw(dwRva, 1, &dwStrRaw));
		RBSURE(ReadRsrcStrRawU(dwStrRaw, rOutStr, dwMaxLen));
		return TRUE;
	}

	BOOL ReadRsrcStrRawU(TImgRaw dwRaw, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		//IMAGE_RESOURCE_DIR_STRING_U
		TU16 wStrLen = 0;
		RBSURE(ReadDatRaw(dwRaw, &wStrLen, sizeof(wStrLen)));
		RBSURE(wStrLen);	
		
		WCHAR* szTmpBuff = (WCHAR*)alloca((dwMaxLen+1)*sizeof(WCHAR));
		memset(szTmpBuff, 0, (dwMaxLen+1)*sizeof(WCHAR));

		wStrLen = wStrLen < WINPE_MAX_STRING_LENGTH? wStrLen: WINPE_MAX_STRING_LENGTH;
		RBSURE(ReadDatRaw(dwRaw+sizeof(TU16), szTmpBuff, wStrLen*sizeof(WCHAR)));
		
		CHAR* szTmpAnsi = (CHAR*)alloca(dwMaxLen);
		memset(szTmpAnsi, 0, dwMaxLen);
		RBSURE(wcstombs(szTmpAnsi, szTmpBuff, wStrLen));

		rOutStr = szTmpAnsi;
		return TRUE;
	}

	BOOL ReadRsrcStrRawA(TImgRaw dwRaw, TString& rOutStr, TImgSize dwMaxLen = WINPE_MAX_STRING_LENGTH)
	{
		//IMAGE_RESOURCE_DIRECTORY_STRING
		TU16 wStrLen = 0;
		RBSURE(ReadDatRaw(dwRaw, &wStrLen, sizeof(wStrLen)));
		RBSURE(wStrLen);

		CHAR* szTmpBuff = (CHAR*)alloca((dwMaxLen+1)*sizeof(CHAR));
		memset(szTmpBuff, 0, (dwMaxLen+1)*sizeof(CHAR));

		wStrLen = wStrLen < WINPE_MAX_STRING_LENGTH? wStrLen: WINPE_MAX_STRING_LENGTH;
		RBSURE(ReadDatRaw(dwRaw+sizeof(TU16), szTmpBuff, wStrLen*sizeof(CHAR)));

		rOutStr = szTmpBuff;
		return TRUE;
	}


	BOOL ReadThunkDatRva(TImgRva dwRva, TU16* lpHint, TString& rFuncName, TU32 & rNameRVA)
	{
		TImgRaw dwRaw = 0;
		RBSURE(Rva2Raw(dwRva, 1, &dwRaw));
		RBSURE(ReadThunkDatRaw(dwRaw, lpHint, rFuncName, rNameRVA));

		return TRUE;
	}
	BOOL ReadThunkDatRaw(TImgRaw dwRaw, TU16* lpHint, TString& rFuncName, TU32 & rNameRVA )
	{
		if(lpHint) *lpHint = 0;
		rNameRVA = 0;
		rFuncName.clear();

		BOOL	bByHint;
		TU16	wHint = 0;
		TImgRva aDataRva;
		if(IsWow64())
		{
			TImgThkDat64 aThkDat;
			RBSURE(ReadDatRaw(dwRaw, &aThkDat, sizeof(aThkDat)));

			TU64 nOrdinal = aThkDat.u1.Ordinal;
			RBSURE(nOrdinal);	

			if(WINPE_IMAGE_SNAP_BY_ORDINAL64(nOrdinal))
			{
				wHint = WINPE_IMAGE_ORDINAL64(nOrdinal);
				bByHint = TRUE;
			}
			else
			{
				aDataRva  =(TImgRva)aThkDat.u1.AddressOfData;
				bByHint = FALSE;
			}			
		}
		else
		{
			TImgThkDat32 aThkDat;
			RBSURE(ReadDatRaw(dwRaw, &aThkDat, sizeof(aThkDat)));

			TU32 nOrdinal = aThkDat.u1.Ordinal;
			RBSURE(nOrdinal);	

			if(WINPE_IMAGE_SNAP_BY_ORDINAL32(nOrdinal))
			{
				wHint = WINPE_IMAGE_ORDINAL32(nOrdinal);
				bByHint = TRUE;
			}
			else
			{
				aDataRva  =(TImgRva)aThkDat.u1.AddressOfData;
				bByHint = FALSE;
			}		
		}	

		if(bByHint)
		{
			FormatStr(rFuncName, "#%d", wHint);
		}
		else
		{	
			//IMAGE_IMPORT_BY_NAME 			
			RBSURE(ReadDatRva(aDataRva, &wHint, sizeof(wHint)));
			RBSURE(ReadStrRvaA(aDataRva + sizeof(wHint), rFuncName));
			rNameRVA = aDataRva + sizeof(wHint);
		}
		ADDR_ASSIGN(lpHint, wHint);
		return TRUE;
	}


public:
	//////////////////////////////////////////////////////////////////////////
	virtual BOOL FileSize(TU64* lpSize)
	{
		RBSURE(ParseLevel(PPL_IMAGE_FILE));
		ADDR_ASSIGN(lpSize, m_dwFileSize);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	virtual TImgDosHdr* DosHeader(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_HEADERS), NULL);
		ADDR_ASSIGN(lpSize, sizeof(m_aImgMzHdr));
		return &m_aImgMzHdr;
	}

	virtual TImgNtHdrBnd* NtHeaders(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_HEADERS), NULL);
		if(IsWow64())
			ADDR_ASSIGN(lpSize, sizeof(m_aImgNtHdr.X64));
		else
			ADDR_ASSIGN(lpSize, sizeof(m_aImgNtHdr.X32));
		return &m_aImgNtHdr;
	}

	virtual TImgOptHdrBnd* OptionalHeader(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_HEADERS), NULL);
		if(IsWow64())
		{
			ADDR_ASSIGN(lpSize, sizeof(m_aImgNtHdr.X64.OptionalHeader));
			return (TImgOptHdrBnd*)&m_aImgNtHdr.X64.OptionalHeader;			
		}
		else
		{
			ADDR_ASSIGN(lpSize, sizeof(m_aImgNtHdr.X32.OptionalHeader));
			return (TImgOptHdrBnd*)&m_aImgNtHdr.X32.OptionalHeader;					
		}
	}

	virtual TImgFileHdr* FileHeader(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_HEADERS), 0);
		ADDR_ASSIGN(lpSize, sizeof(m_aImgNtHdr.X32.FileHeader));
		return &m_aImgNtHdr.X32.FileHeader;
	}

	virtual BOOL DataDirectoryCount(TU32* lpCount = NULL)
	{
		TImgOptHdrBnd* lpOptHdr = OptionalHeader();
		RBSURE(lpOptHdr);
		if(IsWow64())
		{
			ADDR_ASSIGN(lpCount, lpOptHdr->X64.NumberOfRvaAndSizes);
		}
		else
		{
			ADDR_ASSIGN(lpCount, lpOptHdr->X32.NumberOfRvaAndSizes);
		}	
		return TRUE;
	}

	virtual TImgDatDir* DataDirectory(TU32 dwIndex = 0, TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_HEADERS), NULL);
		RVSURE(dwIndex < IMAGE_NUMBEROF_DIRECTORY_ENTRIES, NULL);

		TImgOptHdrBnd* lpOptHdr = OptionalHeader();
		RBSURE(lpOptHdr);
	
		if(IsWow64())
		{
			RBSURE(dwIndex < lpOptHdr->X64.NumberOfRvaAndSizes);
			TImgDatDir& rImgDatDir = lpOptHdr->X64.DataDirectory[dwIndex];
			ADDR_ASSIGN(lpSize, sizeof(rImgDatDir));
			return &rImgDatDir;
		}
		else
		{
			RBSURE(dwIndex < lpOptHdr->X32.NumberOfRvaAndSizes);
			TImgDatDir& rImgDatDir = lpOptHdr->X32.DataDirectory[dwIndex];
			ADDR_ASSIGN(lpSize, sizeof(rImgDatDir));
			return &rImgDatDir;
		}	
	}	
	virtual BOOL ImageType(TU32 dwTypeMask)
	{
		//////////////////////////////////////////////////////////////////////////
		TImgFileHdr* lpFileHdr = FileHeader();	
		RBSURE(lpFileHdr);

		TU32 nMachine = lpFileHdr->Machine;
		TU32 nCharact = lpFileHdr->Characteristics;
		if(dwTypeMask & PET_IMAGE_X86)
		{			
			RBSURE(nMachine == WINPE_IMAGE_FILE_MACHINE_I386); 
		}		
		else if(dwTypeMask & PET_IMAGE_X64)
		{
			RBSURE(nMachine == WINPE_IMAGE_FILE_MACHINE_AMD64); 
		}

		//////////////////////////////////////////////////////////////////////////
		if(dwTypeMask & PET_IMAGE_EXE)
		{
			RBSURE(nCharact & WINPE_IMAGE_FILE_EXECUTABLE_IMAGE);
		}
		else if(dwTypeMask & PET_IMAGE_DLL)
		{
			RBSURE(nCharact & WINPE_IMAGE_FILE_DLL);
		}

		//////////////////////////////////////////////////////////////////////////
		TImgOptHdrBnd* lpOptHdr = OptionalHeader();
		RBSURE(lpOptHdr);

		TU32 nSubSys = IsWow64()\
			? lpOptHdr->X64.Subsystem
			: lpOptHdr->X32.Subsystem;

		if(dwTypeMask & PET_IMAGE_CUI)
		{
			RBSURE(nSubSys == WINPE_IMAGE_SUBSYSTEM_WINDOWS_CUI);
		}
		else if(dwTypeMask & PET_IMAGE_GUI)
		{
			RBSURE(nSubSys == WINPE_IMAGE_SUBSYSTEM_WINDOWS_GUI);
		}
		else if(dwTypeMask & PET_IMAGE_SYS)
		{
			RBSURE(nSubSys == WINPE_IMAGE_SUBSYSTEM_NATIVE_WINDOWS);
		}

		//////////////////////////////////////////////////////////////////////////
		return TRUE;	
	}

	//////////////////////////////////////////////////////////////////////////
	virtual BOOL ImageBaseVa(TU64* lpImgVa = NULL, TImgSize* lpSize = NULL)
	{
		TImgOptHdrBnd* lpOptHdr = OptionalHeader();
		RBSURE(lpOptHdr);

		if(IsWow64())
		{
			ADDR_ASSIGN(lpImgVa, lpOptHdr->X64.ImageBase);
			ADDR_ASSIGN(lpSize, lpOptHdr->X64.SizeOfImage);
		}
		else
		{
			ADDR_ASSIGN(lpImgVa, lpOptHdr->X32.ImageBase);
			ADDR_ASSIGN(lpSize, lpOptHdr->X32.SizeOfImage);
		}
		return TRUE;		
	}

	virtual BOOL ImageTimeStamp(TU32* lpStamp = NULL)
	{
		TImgFileHdr* lpFileHdr = FileHeader();
		RBSURE(lpFileHdr);

		ADDR_ASSIGN(lpStamp, lpFileHdr->TimeDateStamp);
		return TRUE;
	}

	virtual BOOL ImageChecksum(TU32* lpChksum = NULL)
	{
		TImgOptHdrBnd* lpOptHdr = OptionalHeader();
		RBSURE(lpOptHdr);

		if(IsWow64())
			ADDR_ASSIGN(lpChksum, lpOptHdr->X64.CheckSum);
		else
			ADDR_ASSIGN(lpChksum, lpOptHdr->X32.CheckSum);
		return TRUE;
	}

	virtual BOOL EntryPointRva(TImgRva* lpRva = NULL)
	{
		TImgOptHdrBnd* lpOptHdr = OptionalHeader();
		RBSURE(lpOptHdr);

		TImgRva aEptRva = IsWow64()
			? lpOptHdr->X64.AddressOfEntryPoint
			: lpOptHdr->X32.AddressOfEntryPoint;

		ADDR_ASSIGN(lpRva, aEptRva);
		return TRUE;
	}

	virtual BOOL ImageHeaderSize(TImgSize* lpSize = NULL)
	{
		TImgOptHdrBnd* lpOptHdr = OptionalHeader();
		RBSURE(lpOptHdr);

		TU32 nSize = IsWow64()
			? lpOptHdr->X64.SizeOfHeaders
			: lpOptHdr->X32.SizeOfHeaders;

		ADDR_ASSIGN(lpSize, nSize);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	virtual BOOL AlignSectionAboveRva(TImgRva dwRva, TImgRva* lpOut)
	{
		RBSURE(Result(PPL_IMAGE_HEADERS));
		ADDR_ASSIGN(lpOut, AlignAddrAbove(m_dwSectAlign, dwRva));
		return TRUE;
	}

	virtual BOOL AlignSectionBelowRva(TImgRva dwRva, TImgRva* lpOut)
	{
		RBSURE(Result(PPL_IMAGE_HEADERS));
		ADDR_ASSIGN(lpOut, AlignAddrBelow(m_dwSectAlign, dwRva));
		return TRUE;
	}

	virtual BOOL AlignFileAboveRaw(TImgRaw dwRaw, TImgRaw* lpOut)
	{
		RBSURE(Result(PPL_IMAGE_HEADERS));
		ADDR_ASSIGN(lpOut, AlignAddrAbove(m_dwFileAlign, dwRaw));
		return TRUE;
	}

	virtual BOOL AlignFileBelowRaw(TImgRaw dwRaw, TImgRaw* lpOut)
	{
		RBSURE(Result(PPL_IMAGE_HEADERS));
		ADDR_ASSIGN(lpOut, AlignAddrBelow(m_dwFileAlign, dwRaw));
		return TRUE;
	}

	virtual BOOL AlignRelocAboveRva(TImgRva dwRva, TImgRva* lpOut)
	{
		ADDR_ASSIGN(lpOut, AlignAddrAbove(WINPE_RELOCATION_PAGE_SIZE, dwRva));
		return TRUE;
	}
	virtual BOOL AlignRelocBelowRva(TImgRva dwRva, TImgRva* lpOut)
	{
		ADDR_ASSIGN(lpOut, AlignAddrBelow(WINPE_RELOCATION_PAGE_SIZE, dwRva));
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	virtual TImgSecHdr* SectionHeader(TU32 dwIndex = 0, TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_SECTIONS), NULL);
		RVSURE(dwIndex < m_aImgSecHdrLst.size(), NULL);

		TImgSecHdr& rImgSecHdr = m_aImgSecHdrLst[dwIndex];
		ADDR_ASSIGN(lpSize, sizeof(rImgSecHdr));
		return &rImgSecHdr;
	}

	virtual BOOL SectionCount(TU32* lpCount = NULL)
	{
		RBSURE(Result(PPL_IMAGE_SECTIONS));
		ADDR_ASSIGN(lpCount, m_aImgSecHdrLst.size());
		return TRUE;
	}	
	virtual BOOL SectionRva(TU32 dwIndex, TImgRva* lpRva = NULL, TImgSize* lpSize = NULL)
	{	
		IMAGE_SECTION_HEADER* lpSecHdr = SectionHeader(dwIndex);
		RBSURE(lpSecHdr);

		ADDR_ASSIGN(lpRva, lpSecHdr->VirtualAddress);
		ADDR_ASSIGN(lpSize, lpSecHdr->Misc.VirtualSize);
		return TRUE;
	}

	virtual BOOL SectionRaw(TU32 dwIndex, TImgRaw* lpRaw = NULL, TImgSize* lpSize = NULL)
	{
		IMAGE_SECTION_HEADER* lpSecHdr = SectionHeader(dwIndex);
		RBSURE(lpSecHdr);

		ADDR_ASSIGN(lpRaw, lpSecHdr->PointerToRawData);
		ADDR_ASSIGN(lpSize, lpSecHdr->SizeOfRawData);
		return TRUE;
	}

	virtual LPCSTR SectionName(TU32 dwIndex)
	{
		RVSURE(Result(PPL_IMAGE_SECTIONS), NULL);
		if(dwIndex >= m_aImgSecNameLst.size())
			return NULL;

		return m_aImgSecNameLst[dwIndex].c_str();
	}

	//////////////////////////////////////////////////////////////////////////
	virtual BOOL OverlayRaw(TImgRaw* lpRaw = NULL, TImgSize* lpSize = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_FILE));
		RBSURE(ParseLevel(PPL_IMAGE_SECTIONS));

		RBSURE(m_dwMaxSectRaw && m_dwFileSize);
		RBSURE(m_dwMaxSectRaw > m_dwFileSize);
		ADDR_ASSIGN(lpSize, (TImgSize)(m_dwMaxSectRaw - m_dwFileSize));
		ADDR_ASSIGN(lpRaw, m_dwMaxSectRaw);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 01. Export Data Directory
	virtual TImgExpDir* ExportDirectory(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_EXPORT), NULL);
		ADDR_ASSIGN(lpSize, sizeof(m_aImgExpDir));
		return &m_aImgExpDir;
	}

	virtual LPCSTR ExportModule()
	{
		RVSURE(ParseLevel(PPL_IMAGE_EXPORT), NULL);
		RVSURE(!m_sExportModule.empty(), NULL);
		return m_sExportModule.c_str();
	}

	virtual BOOL IsExportModule(LPCSTR szModule)
	{
		LPCSTR szCurName = ExportModule();
		RBSURE(szCurName);

		RBSURE(stricmp(szCurName, szModule) == 0);
		return TRUE;
	}

	virtual BOOL ExportFunctionCount(TU32* lpCount = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_EXPORT));
		ADDR_ASSIGN(lpCount, m_aExportMap.size());
		return TRUE;
	}
	virtual LPCSTR ExportFunctionNext(LPCSTR szLastFunc = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_EXPORT), NULL);
		return NextMapStrKey(m_aExportMap, szLastFunc);
	}

	virtual BOOL IsExportFunction(LPCSTR szFunction)
	{
		RBSURE(ParseLevel(PPL_IMAGE_EXPORT));
		RBSURE(FindMapStrKey(m_aExportMap, szFunction));
		return TRUE;
	}

	virtual BOOL ExportFunctionRva(LPCSTR szFuncName, TImgRva* lpRva = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_EXPORT));
		TFuncMap::iterator fitr = m_aExportMap.find(szFuncName);
		RBSURE(fitr != m_aExportMap.end());
		ADDR_ASSIGN(lpRva, fitr->second.dwAddrRva);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 02. Import Data Directory
	virtual TImgImpDes* ImportDirectory(LPCSTR szModule, TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_IMPORT), NULL);
		RVSURE(szModule, NULL);
		LPVOID lpRetDir = FindMapStrKey(m_aImgImpMap, szModule);
		RVSURE(lpRetDir, NULL);
		ADDR_ASSIGN(lpSize, sizeof(TImgImpDes));
		return (TImgImpDes*)lpRetDir;
	}	

	virtual BOOL ImportCount(DWORD* lpLibCount = NULL, DWORD* lpFuncCount = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_IMPORT));
		ADDR_ASSIGN(lpLibCount, m_aImgImpMap.size());
		if( lpFuncCount )
		{
			TModuleMap::iterator it = m_aImportMap.begin();
			for( ; it != m_aImportMap.end(); ++ it )
			{
				*lpFuncCount += it->second.size();
			}
		}
		return TRUE;
	}

	virtual LPCSTR NextImportModule(LPCSTR szLastModu = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_IMPORT), NULL);
		return NextMapStrKey(m_aImportMap, szLastModu);
	}

	virtual BOOL IsImportFunction(LPCSTR szModule, LPCSTR szFunction)
	{
		RBSURE(ParseLevel(PPL_IMAGE_IMPORT));
		RBSURE(FindMapStrKey(m_aImportMap, szModule, szFunction));
		return TRUE;
	}
	virtual LPCSTR NextImportFunction(LPCSTR szModule, LPCSTR szLastFunc = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_IMPORT), NULL);
		return NextMapStrKey(m_aImportMap, szModule, szLastFunc);
	}

	virtual BOOL ImportFunctionCount(LPCSTR szModule, TU32* lpCount = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_IMPORT));

		TFuncMap* lpFuncMap = (TFuncMap*)FindMapStrKey(m_aImportMap, szModule);
		RBSURE(lpFuncMap);

		ADDR_ASSIGN(lpCount, lpFuncMap->size());
		return TRUE;
	}
	virtual BOOL ImportFunctionSlotRva(LPCSTR szModule, LPCSTR szFuncName, TImgRva* lpRva = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_IMPORT));
		TFuncEnt* lpFuncEnt = (TFuncEnt*)FindMapStrKey(m_aImportMap, szModule, szFuncName);
		RBSURE(lpFuncEnt);
		ADDR_ASSIGN(lpRva, lpFuncEnt->dwAddrRva);
		return TRUE;
	}
	virtual BOOL ImportFunctionNameRVA(LPCSTR szModule, LPCSTR szFuncName, DWORD* lpRva )
	{
		RBSURE(ParseLevel(PPL_IMAGE_IMPORT));
		TFuncEnt* lpFuncEnt = (TFuncEnt*)FindMapStrKey(m_aImportMap, szModule, szFuncName);
		RBSURE(lpFuncEnt);
		if( !lpFuncEnt->nameRVA ) return FALSE;
		ADDR_ASSIGN(lpRva, lpFuncEnt->nameRVA);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 03. Resource Data Directory
	virtual BOOL ResourceRva(LPCSTR szType, LPCSTR szNameId, LPCSTR szLang, TImgRva* lpRva = NULL, TU32* lpSize = NULL)
	{
		TWinResEnt* lpResEnt = ResourceEntry(szType, szNameId, szLang);
		RBSURE(lpResEnt);
		
		TWinResDat* lpResDat = lpResEnt->SubData();
		RBSURE(lpResDat);
	
		ADDR_ASSIGN(lpRva, lpResDat->DatRva);
		ADDR_ASSIGN(lpSize, lpResDat->DatLen);
		return TRUE;
	}

	virtual LPCSTR NextResourceType(LPCSTR szLast = NULL)
	{
		TWinResEnt* lpRootEnt = ResourceRootEntry();
		RVSURE(lpRootEnt, NULL);
		return lpRootEnt->SubNext(szLast);;
	}

	virtual LPCSTR NextResourceNameId(LPCSTR szType, LPCSTR szLast = NULL)
	{
		TWinResEnt* lpTypeEnt = ResourceTypeEntry(szType);
		RVSURE(lpTypeEnt, NULL);
		return lpTypeEnt->SubNext(szLast);
	}

	virtual LPCSTR NextResourceLanguage(LPCSTR szType, LPCSTR szNameId, LPCSTR szLast = NULL)
	{
		TWinResEnt* lpNameIdEnt = ResourceNameIdEntry(szType, szNameId);
		RVSURE(lpNameIdEnt, NULL);
		return lpNameIdEnt->SubNext(szLast);
	}

	virtual BOOL ResourceCount(TU32* lpCount = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_RESOURCE));
		ADDR_ASSIGN(lpCount, m_dwRrscDataCnt);
		return TRUE;
	}
	virtual BOOL ResourceTypeCount(TU32* lpCount = NULL)
	{
		TWinResEnt* lpRootEnt = ResourceRootEntry();
		RBSURE(lpRootEnt);

		TWinResLst* lpRootLst = lpRootEnt->SubList();
		RBSURE(lpRootLst);

		ADDR_ASSIGN(lpCount, lpRootLst->Count());
		return TRUE;
	}

	virtual BOOL ResourceNameIdCount(LPCSTR szType, TU32* lpCount = NULL)
	{
		TWinResEnt* lpTypeEnt = ResourceTypeEntry(szType);
		RBSURE(lpTypeEnt);

		TWinResLst* lpTypeLst = lpTypeEnt->SubList();
		RBSURE(lpTypeLst);

		ADDR_ASSIGN(lpCount, lpTypeLst->Count());
		return TRUE;
	}

	virtual BOOL ResourceLanguageCount(LPCSTR szType, LPCSTR szNameId, TU32* lpCount = NULL)
	{
		TWinResEnt* lpNameEnt = ResourceNameIdEntry(szType, szNameId);
		RBSURE(lpNameEnt);

		TWinResLst* lpNameLst = lpNameEnt->SubList();
		RBSURE(lpNameLst);

		ADDR_ASSIGN(lpCount, lpNameLst->Count());
		return TRUE;
	}

	virtual TImgResDir* ResourceTypeDirectory(TU32* lpSize = NULL)
	{
		TWinResEnt* lpRootEnt = ResourceRootEntry();
		RVSURE(lpRootEnt, NULL);

		TWinResLst* lpRootLst = lpRootEnt->SubList();
		RVSURE(lpRootLst, NULL);

		return lpRootLst->Header();
	}	

	virtual TImgResDir* ResourceNameIdDirectory(LPCSTR szType, TU32* lpSize = NULL)
	{
		TWinResEnt* lpTypeEnt = ResourceTypeEntry(szType);
		RVSURE(lpTypeEnt, NULL);

		TWinResLst* lpTypeLst = lpTypeEnt->SubList();
		RVSURE(lpTypeLst, NULL);

		return lpTypeLst->Header();
	}

	virtual TImgResDir* ResourceLanguageDirectory(LPCSTR szType, LPCSTR szNameId, TU32* lpSize = NULL)
	{
		TWinResEnt* lpNameEnt = ResourceNameIdEntry(szType, szNameId);
		RVSURE(lpNameEnt, NULL);

		TWinResLst* lpNameLst = lpNameEnt->SubList();
		RVSURE(lpNameLst, NULL);

		return lpNameLst->Header();
	}

	virtual LPCSTR ResourcePath(LPSTR szBuff, TU32 nMaxCch, LPCSTR szType = NULL, LPCSTR szNameId = NULL, LPCSTR szLang = NULL)
	{
		TU32 nPathOff = 0;
		memset(szBuff, 0, nMaxCch);
		
		if(szType)
		{
			if(RSRC_IS_ID(szType))
				nPathOff +=_snprintf(&szBuff[nPathOff], nMaxCch - nPathOff, "#%d", RSRC_IS_ID(szType));
			else
				nPathOff +=_snprintf(&szBuff[nPathOff], nMaxCch - nPathOff, "%s", szType);

			if(szNameId)
			{
				if(RSRC_IS_ID(szNameId))
					nPathOff +=_snprintf(&szBuff[nPathOff], nMaxCch - nPathOff, "\\#%d", RSRC_IS_ID(szNameId));
				else
					nPathOff +=_snprintf(&szBuff[nPathOff], nMaxCch - nPathOff, "\\%s", szNameId);

				if(szLang)
				{
					if(RSRC_IS_ID(szLang))
						nPathOff +=_snprintf(&szBuff[nPathOff], nMaxCch - nPathOff, "\\#%d", RSRC_IS_ID(szLang));
					else
						nPathOff +=_snprintf(&szBuff[nPathOff], nMaxCch - nPathOff, "\\%s", szLang);
				}
			}
		}
		return szBuff;	
	}
		
	//////////////////////////////////////////////////////////////////////////
	// 04. Exception Table

	//////////////////////////////////////////////////////////////////////////
	// 05. Certificate Table
	virtual TImgCrtDir* CertificateDirectory(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_CERTIFICATE), NULL);
		ADDR_ASSIGN(lpSize, sizeof(m_aWinCertHdr));
		return &m_aWinCertHdr;
	}
	virtual BOOL CertificateData(TImgRaw* lpRaw = NULL, TImgSize* lpSize = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_CERTIFICATE));
		ADDR_ASSIGN(lpRaw, m_dwCertRaw);
		ADDR_ASSIGN(lpSize, m_dwCertLen);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 06. Base Relocation Table
	static int __cdecl RelocEntCmp(const void* lpLft, const void* lpRgt) 
	{
		int nLft = IMAGE_REL_OFFSET(*(TU16*)lpLft);
		int nRgt = IMAGE_REL_OFFSET(*(TU16*)lpRgt);
		return nLft - nRgt;
	}
	virtual BOOL IsRelocRva(TImgRva dwRva)
	{
		RBSURE(ParseLevel(PPL_IMAGE_RELOCATION));

		TU16 wBlkOff = (TU16)(dwRva & 0xFFF);
		TU32 dwBlkRva = dwRva - wBlkOff;

		TRelocMap::iterator mitr = m_aRelocMap.find(dwBlkRva);
		RBSURE(mitr != m_aRelocMap.end());

		TRelocBlock& rRlcBlk = mitr->second;
		TU16* lpTarItm = (TU16*)bsearch(&wBlkOff, &rRlcBlk[0], rRlcBlk.size(), sizeof(TU16), &RelocEntCmp);
		RBSURE(lpTarItm);
		return TRUE;
	}

	virtual BOOL RelocDelta(TU64 dwNewBase, LONG* lpDelta = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_RELOCATION));
		ADDR_ASSIGN(lpDelta, 0);

		TU64 dwCurBase = 0;
		RBSURE(ImageBaseVa(&dwCurBase));

		if(dwNewBase > dwCurBase)
			ADDR_ASSIGN(lpDelta, (LONG)(dwNewBase - dwCurBase));
		else
			ADDR_ASSIGN(lpDelta, -(LONG)(dwCurBase - dwNewBase));

		return TRUE;
	}

	virtual BOOL RelocBlock(LONG lDelta, TImgRva dwBuffRva, LPVOID lpBuff, TImgSize dwSize)
	{
		RBSURE(ParseLevel(PPL_IMAGE_RELOCATION));

		TImgRva		dwCurRva = dwBuffRva;
		TU08*		lpCurBuf = (TU08*)lpBuff;
		TImgSize	dwLeft	= dwSize;

		while(dwLeft > 0)
		{
			TImgSize	dwDone	= 0;
			if(!RelocSinglePage(lDelta, dwCurRva, lpCurBuf, dwLeft, &dwDone))
				break;

			dwLeft	 -= dwDone;
			lpCurBuf += dwDone;
			dwCurRva += dwDone;
		};
		return TRUE;
	}

	virtual BOOL RelocSinglePage(LONG lDelta, TImgRva dwBufRva, LPVOID lpBuff, TImgSize dwSize, TImgSize* lpDone = NULL)
	{	
		RBSURE(ParseLevel(PPL_IMAGE_RELOCATION));

		ADDR_ASSIGN(lpDone, 0);
		TImgRva dwPageRva = 0;
		RBSURE(AlignRelocAboveRva(dwBufRva, &dwPageRva));

		TImgSize dwPathSize = min(dwSize, WINPE_RELOCATION_PAGE_SIZE);
		ADDR_ASSIGN(lpDone, dwPathSize);

		TRelocMap::iterator mitr = m_aRelocMap.find(dwPageRva);
		if(mitr == m_aRelocMap.end())
			return TRUE;

		TU08* lpBytBuf = (TU08*)lpBuff;
		TRelocBlock& rRlcBlk = mitr->second;
		
		TU16 wBegOff = (TU16)(dwBufRva - dwPageRva);
		TU16 wEndOff = (TU16)(wBegOff + dwPathSize);

		TU32 dwPthCnt = 0;
		TU32 dwRlcCnt = rRlcBlk.size();
		for(TU32 n = 0; n < dwRlcCnt; n++)
		{
			TU16 wRlcItm = rRlcBlk[n];
			TU16 wOffs = (wRlcItm & 0x0FFF);
			TU16 wType = ((wRlcItm & 0xF000)>>12);

			if(wOffs < wBegOff)
				continue;			

			TU16 wBufOff = wOffs - wBegOff;
			if(wType == IMAGE_REL_BASED_ABSOLUTE)
			{
				continue;
			}
			else if(wType == IMAGE_REL_BASED_HIGH)
			{
				if(wOffs + sizeof(TU16) > wEndOff)
					break;

				*(TU16*)(&lpBytBuf[wBufOff]) += (TU16)(lDelta>>16);
			}
			else if(wType == IMAGE_REL_BASED_LOW)
			{
				if(wOffs + sizeof(TU16) > wEndOff)
					break;

				*(TU16*)(&lpBytBuf[wBufOff]) += (TU16)(lDelta&0xFFFF);
				dwPthCnt++;
			}
			else if(wType == IMAGE_REL_BASED_HIGHLOW)
			{
				if(wOffs + sizeof(TU32) > wEndOff)
					break;

				*(TU32*)(&lpBytBuf[wBufOff]) += lDelta;
				dwPthCnt++;
			}	
			else
			{
				if(wOffs >= wEndOff)
					break;
				continue;
			}
		}
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 07. Debug Data Directory
	virtual TImgDbgDir* DebugDirectory(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_DEBUG), NULL);
		ADDR_ASSIGN(lpSize, sizeof(m_aImgDbgDir));
		return &m_aImgDbgDir;
	}

	virtual LPCSTR DebugFilePath()
	{
		RVSURE(ParseLevel(PPL_IMAGE_DEBUG), NULL);
		RVSURE(!m_sDebugFilePath.empty(), NULL);
		return m_sDebugFilePath.c_str();
	}

	//////////////////////////////////////////////////////////////////////////
	// 08. Architecture (Reserved)

	//////////////////////////////////////////////////////////////////////////
	// 09. Global Ptr (Reserved)

	//////////////////////////////////////////////////////////////////////////
	// 10. TLS Table
	virtual TImgTlsDirBnd* TlsDirectory(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_TLS), NULL);
		if(IsWow64())
			ADDR_ASSIGN(lpSize, sizeof(m_aImgTlsDir.X64));
		else
			ADDR_ASSIGN(lpSize, sizeof(m_aImgTlsDir.X32));
		return &m_aImgTlsDir;
	}

	virtual BOOL TlsTempleteRva(TImgRva* lpRva = NULL, TImgSize* lpSize = NULL)
	{
		TImgTlsDirBnd* lpTlsDir = TlsDirectory();
		RBSURE(lpTlsDir);

		TU64 dwTmpBegVa = 0, dwTmpEndVa = 0;
		if(IsWow64())
		{
			dwTmpBegVa = lpTlsDir->X64.StartAddressOfRawData;
			dwTmpEndVa = lpTlsDir->X64.EndAddressOfRawData;			
		}
		else
		{
			dwTmpBegVa = lpTlsDir->X32.StartAddressOfRawData;
			dwTmpEndVa = lpTlsDir->X32.EndAddressOfRawData;	
		}
		RBSURE(dwTmpBegVa > 0 && dwTmpEndVa > 0);

		TU32 dwTmpSize = (TU32)(dwTmpEndVa - dwTmpBegVa); 
		RBSURE(dwTmpEndVa >= dwTmpBegVa);

		TImgRva dwTmpRva = 0;
		RBSURE(Va2Rva(dwTmpBegVa, dwTmpSize, &dwTmpRva));

		ADDR_ASSIGN(lpRva, dwTmpRva);
		ADDR_ASSIGN(lpSize, dwTmpSize);		
		return TRUE;
	}

	virtual BOOL TlsCallBackCount(TU32* lpCount = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_TLS));
		ADDR_ASSIGN(lpCount, m_aTlsFuncLst.size());
		return TRUE;
	}

	virtual BOOL TlsCallBackRva(TU32 dwIndex, TImgRva* lpRva = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_TLS));
		RBSURE(dwIndex < m_aTlsFuncLst.size());
		ADDR_ASSIGN(lpRva, m_aTlsFuncLst[dwIndex]);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 11. Load Config Table
	virtual TImgCfgDirBnd* LoadConfigDirectory(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_LOADCONFIG), NULL);
		if(IsWow64())
			ADDR_ASSIGN(lpSize, sizeof(m_aImgCfgDir.X64));
		else
			ADDR_ASSIGN(lpSize, sizeof(m_aImgCfgDir.X32));
		return &m_aImgCfgDir;
	}

	virtual BOOL SehHandlerCount(TU32* lpCount = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_LOADCONFIG));
		ADDR_ASSIGN(lpCount, m_aImgSehHdlLst.size());
		return TRUE;
	}

	virtual BOOL SehHandlerRva(TU32 dwIndex, TImgRva* lpRva = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_LOADCONFIG));
		RBSURE(dwIndex < m_aImgSehHdlLst.size());
		ADDR_ASSIGN(lpRva, m_aImgSehHdlLst[dwIndex]);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 12. Bound Import Table
	virtual TImgBndDes* BoundImportDescriptor(LPCSTR szModule, TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_BOUNDIMPORT), NULL);
		TImgBndDes** lppBndDes = (TImgBndDes**)FindMapStrKey(m_aBndModNameMap, szModule);
		RVSURE(lppBndDes && *lppBndDes, NULL);
		ADDR_ASSIGN(lpSize, sizeof(TImgBndDes));
		return *lppBndDes;
	}

	virtual BOOL BoundModuleCount(TU32* lpCount)
	{
		RBSURE(ParseLevel(PPL_IMAGE_BOUNDIMPORT));
		ADDR_ASSIGN(lpCount, m_aBndModNameMap.size());
		return TRUE;
	}

	virtual LPCSTR NextBoundModule(LPCSTR szLast = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_BOUNDIMPORT), NULL);
		return NextMapStrKey(m_aBndModNameMap, szLast);
	}

	virtual BOOL BoundTimeStamp(LPCSTR szModule, TImgTms* lpTms)
	{
		TImgBndDes* lpBndDes = BoundImportDescriptor(szModule);
		RBSURE(lpBndDes);		
		ADDR_ASSIGN(lpTms, lpBndDes->TimeDateStamp);
		return TRUE;
	}

	virtual BOOL BoundForwardCount(LPCSTR szModule, TU32* lpCount)
	{
		TImgBndDes* lpBndDes = BoundImportDescriptor(szModule);
		RBSURE(lpBndDes);
		ADDR_ASSIGN(lpCount, lpBndDes->NumberOfModuleForwarderRefs);
		return TRUE;
	}

	virtual LPCSTR BoundForwardModule(LPCSTR szModule, TU32 nIndex)
	{
		TImgBndDes* lpBndDes = BoundImportDescriptor(szModule);
		RVSURE(lpBndDes, NULL);
		RVSURE(lpBndDes->NumberOfModuleForwarderRefs, NULL);	

		TImgBndDes* lpBndFwd = &lpBndDes[nIndex + 1];
		TU16 wOffset = lpBndFwd->OffsetModuleName;

		TImgBndNameMap::iterator mitr = m_aBndFwdNameMap.find(wOffset);
		RVSURE(mitr != m_aBndFwdNameMap.end(), NULL);

		TString& rFwdName = mitr->second;
		return rFwdName.c_str();
	}	

	//////////////////////////////////////////////////////////////////////////
	// 13. Import Address Table
	virtual BOOL IsImportFunctionSlotRva(TImgRva dwRva)
	{
		RBSURE(ParseLevel(PPL_IMAGE_IMPORT));

		TImgRva dwTabBegRva = 0, dwTabEndRva = 0;
		TImgSize dwTabSize = 0;
		RBSURE(ImportAddresTable(&dwTabBegRva, &dwTabSize));
		dwTabEndRva += dwTabSize;

		RBSURE(dwRva >= dwTabBegRva && dwRva < dwTabEndRva);

		TU32 nSlotLen = IsWow64()? sizeof(TU64): sizeof(TU32);
		RBSURE((dwRva - dwTabBegRva) % nSlotLen == 0);
		return FALSE;
	}
	virtual BOOL ImportAddresTable(TImgRva* lpRva = NULL, TImgSize* lpSize = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_IMPORT));

		TImgDatDir* lpDatDir = DataDirectory(IMAGE_DIRECTORY_ENTRY_IAT);
		RBSURE(lpDatDir);
		RBSURE(IsValidRva(lpDatDir->VirtualAddress, lpDatDir->Size));

		ADDR_ASSIGN(lpSize, lpDatDir->Size);
		ADDR_ASSIGN(lpRva, lpDatDir->VirtualAddress);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 14. Delay Import Descriptor
	virtual TImgDlyDes* DelayImportDescriptor(LPCSTR szModule, TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_DELAYIMPORT), NULL);
		RVSURE(szModule, NULL);
		LPVOID lpRetDes = FindMapStrKey(m_aImgDlyMap, szModule);
		RVSURE(lpRetDes, NULL);
		ADDR_ASSIGN(lpSize, sizeof(TImgDlyDes));
		return (TImgDlyDes*)lpRetDes;		
	}
	virtual BOOL DelayImportCount(TU32* lpCount = NULL)
	{
		RBSURE(ParseLevel(PPL_IMAGE_DELAYIMPORT));
		ADDR_ASSIGN(lpCount, m_aImgDlyMap.size());
		return TRUE;
	}

	virtual LPCSTR NextDelayModule(LPCSTR szLast = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_DELAYIMPORT), NULL);
		return NextMapStrKey(m_aDlyFucMap, szLast);
	}

	virtual LPCSTR NextDelayFunction(LPCSTR szModule, LPCSTR szLast = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_DELAYIMPORT), NULL);
		return NextMapStrKey(m_aDlyFucMap, szModule, szLast);
	}

	virtual BOOL DelayFunctionSlotRva(LPCSTR szModule, LPCSTR szFuncName, TImgRva* lpRva = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_DELAYIMPORT), NULL);
		TFuncEnt* lpFuncEnt = (TFuncEnt*)FindMapStrKey(m_aDlyFucMap, szModule, szFuncName);
		RBSURE(lpFuncEnt);

		ADDR_ASSIGN(lpRva, lpFuncEnt->dwAddrRva);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	// 15. CLR Runtime Header 
	virtual TImgClrDir* ClrRuntimeDirectory(TU32* lpSize = NULL)
	{
		RVSURE(ParseLevel(PPL_IMAGE_CLRRUNTIME), NULL);
		ADDR_ASSIGN(lpSize, sizeof(m_aImgClrHdr));
		return &m_aImgClrHdr;
	}

	//////////////////////////////////////////////////////////////////////////
protected:
	template<class TStrMap>
	static LPCSTR inline NextMapStrKey(TStrMap& rStrMap, LPCSTR szL1Last)
	{
		TStrMap::iterator mitr;		
		if(!szL1Last)
		{
			mitr = rStrMap.begin();
			if(mitr == rStrMap.end())
				return NULL;
		}
		else
		{	
			mitr = rStrMap.find(szL1Last);
			if(mitr == rStrMap.end())
				mitr = rStrMap.begin();
			else
				mitr++;

			if(mitr == rStrMap.end())
				return NULL;	
		}
		return mitr->first.c_str();
	}

	template<class TStrMap>
	static LPCSTR inline NextMapStrKey(TStrMap& rStrMap, LPCSTR szL1Last, LPCSTR szL2Last)
	{
		TStrMap::iterator mitr;
		if(szL1Last)
			mitr = rStrMap.find(szL1Last);
		else
			mitr = rStrMap.begin();

		if(mitr == rStrMap.end())
			return NULL;

		TStrMap::referent_type& rFuncMap = mitr->second;
		return NextMapStrKey(rFuncMap, szL2Last);
	}

	template<class TStrMap>
	static LPVOID inline FindMapStrKey(TStrMap& rStrMap, LPCSTR szL1Key)
	{
		TStrMap::iterator mitr = rStrMap.find(szL1Key);
		if(mitr == rStrMap.end())
			return NULL;

		return &(mitr->second);
	}

	template<class TStrMap>
	static LPVOID inline FindMapStrKey(TStrMap& rStrMap, LPCSTR szL1Key, LPCSTR szL2Key)
	{
		TStrMap::iterator mitr = rStrMap.find(szL1Key);
		if(mitr == rStrMap.end())
			return NULL;

		typedef typename TStrMap::referent_type TStrMapL2;
		TStrMapL2& rFuncMap = mitr->second;
		TStrMapL2::iterator fitr = rFuncMap.find(szL2Key);
		if(fitr == rFuncMap.end())
			return NULL;

		return &(fitr->second);
	}	

	template<typename TAlgn, typename TAddr>
	static TAddr inline AlignAddrBelow(TAlgn Algn, TAddr Addr)
	{
		if(Addr % Algn == 0)
			return Addr;
		else
			return ((Addr/Algn) + 1) * Algn;		 
	}

	template<typename TAlgn, typename TAddr>
	static TAddr inline AlignAddrAbove(TAlgn Algn, TAddr Addr)
	{
		if(Addr % Algn == 0)
			return Addr;
		else
			return (Addr/Algn) * Algn;	 
	}
protected:
	//////////////////////////////////////////////////////////////////////////
	static VOID FormatStr(TString& rOutStr, LPCSTR szFormat, ...)
	{
		va_list vArgLst;
		va_start(vArgLst, szFormat);

		CHAR szStrBuff[WINPE_MAX_STRING_LENGTH];
		vsnprintf(szStrBuff, sizeof(szStrBuff), szFormat, vArgLst);
		rOutStr = szStrBuff;

		va_end(vArgLst);
	}

	//////////////////////////////////////////////////////////////////////////
	static TParseItem* ParseRules(TU32 dwIndex = 0)
	{
		static TParseItem g_aParseList[] = \
		{
			{PPL_IMAGE_FILE,			&TThis::ParseFile,			&TThis::ClearFile,			0													},
			{PPL_IMAGE_HEADERS,			&TThis::ParseHeaders,		&TThis::ClearHeaders,		PPL_IMAGE_FILE										},
			{PPL_IMAGE_SECTIONS,		&TThis::ParseSections,		&TThis::ClearSections,		PPL_IMAGE_FILE|PPL_IMAGE_HEADERS					},
			{PPL_IMAGE_IMPORT,			&TThis::ParseImport,		&TThis::ClearImport,		PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_EXPORT,			&TThis::ParseExport,		&TThis::ClearExport,		PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_RESOURCE,		&TThis::ParseResource,		&TThis::ClearResource,		PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_TLS,				&TThis::ParseTls,			&TThis::ClearTls,			PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_DEBUG,			&TThis::ParseDebug,			&TThis::ClearDebug,			PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_RELOCATION,		&TThis::ParseRelocation,	&TThis::ClearRelocation,	PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_DELAYIMPORT,		&TThis::ParseDelayImport,	&TThis::ClearDelayImport,	PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_LOADCONFIG,		&TThis::ParseLoadConfig,	&TThis::ClearLoadConfig,	PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_CERTIFICATE,		&TThis::ParseCertificate,	&TThis::ClearCertificate,	PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_BOUNDIMPORT,		&TThis::ParseBoundImport,	&TThis::ClearBoundImport,	PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},
			{PPL_IMAGE_CLRRUNTIME,		&TThis::ParseClrRuntime,	&TThis::ClearClrRuntime,	PPL_IMAGE_FILE|PPL_IMAGE_HEADERS|PPL_IMAGE_SECTIONS	},			
			{0,							NULL,						NULL,						0}
		};

		TParseItem* lpItem = &g_aParseList[dwIndex];
		if(lpItem->dwLevMask == 0 && lpItem->fnParser == NULL)
			return NULL;

		return lpItem;
	}

	BOOL ParseItem(TParseItem* lpItem)
	{
		if(!lpItem)
			return FALSE;

		TU32 dwLevMask = lpItem->dwLevMask;
		if(Result(dwLevMask))
			return TRUE;

		if(Touch(dwLevMask))
			return FALSE;

		m_dwTouchLevel |= dwLevMask;
		m_dwParseResult &= ~dwLevMask;

		TParsePtr fnParse= lpItem->fnParser;
		if(!fnParse)
			return FALSE;
		
		if(!(this->*fnParse)())
			return TRUE;
			
		m_dwParseResult |= dwLevMask;
		return TRUE;
	}

	BOOL ParseLevel(TU32 dwLevel)
	{
		if(Result(dwLevel))
			return TRUE;

		if(Touch(dwLevel))
			return FALSE;

		TParseItem* lpTarItem = NULL;
		for(TU32 n = 0;; n++)
		{
			TParseItem* lpCurItem = ParseRules(n);
			if(!lpCurItem)
				break;

			if(lpCurItem->dwLevMask != dwLevel)
				continue;
			
			lpTarItem = lpCurItem;
			break;
		}
		RBSURE(lpTarItem);

		for(TU32 n = 0;; n++)
		{
			TParseItem* lpCurItem = ParseRules(n);
			if(!lpCurItem)
				break;

			if(!(lpCurItem->dwLevMask & lpTarItem->dwLevDepend))
				break;

			if(!ParseItem(lpCurItem))
				return FALSE;
		}
		RBSURE(ParseItem(lpTarItem));
		return TRUE;
	}

	BOOL Parse(TU32 dwLevel)
	{	
		if(m_dwParseResult & dwLevel)
			return TRUE;

		m_dwTouchLevel	= 0;
		m_dwParseResult  = 0;	

		for(TU32 n = 0; ; n++)
		{
			TParseItem* lpCurItem = ParseRules(n);
			if(!lpCurItem)
				break;

			if(!(lpCurItem->dwLevMask & dwLevel))
				break;

			if(!ParseItem(lpCurItem))
				break;
		}

		RBSURE(Result(PPL_IMAGE_FILE|PPL_IMAGE_HEADERS));
		return TRUE;		
	}

	VOID ClearItem(TParseItem* lpItem)
	{
		if(!lpItem)
			return;

		TClearPtr fnClean = lpItem->fnClear;
		if(!fnClean)
			return;

		(this->*fnClean)();
	}
	VOID Clear()
	{
		m_dwParseResult = 0;
		m_dwTouchLevel = 0;

		for(TU32 n = 0;; n++)
		{
			TParseItem* lpItem = ParseRules(n);
			if(!lpItem)
				break;

			ClearItem(lpItem);
		}	
	}
	//////////////////////////////////////////////////////////////////////////
	BOOL ParseFile()
	{
		TStream* lpStream = Stream();
		RBSURE(lpStream);

		TU64 dwFileSize = lpStream->Length();
		if( dwFileSize == LENGTH_ERROR ) return FALSE;

		m_dwFileSize = dwFileSize;
		return TRUE;
	}

	VOID ClearFile()
	{
		m_dwFileSize = 0;
	}
	//////////////////////////////////////////////////////////////////////////
	BOOL ParseHeaders()
	{
		RBSURE(Result(PPL_IMAGE_FILE));
		RBSURE(ReadDatRaw(0, &m_aImgMzHdr, sizeof(m_aImgMzHdr)));
		RBSURE(m_aImgMzHdr.e_magic == IMAGE_DOS_SIGNATURE);

		TImgRaw nFileRaw = m_aImgMzHdr.e_lfanew;
		TU32 nFstHdrLen = sizeof(TImgNtHdr32) - sizeof(TImgOptHdr32);
		RBSURE(ReadDatRaw(nFileRaw, &m_aImgNtHdr, nFstHdrLen));
		RBSURE(m_aImgNtHdr.X32.Signature == IMAGE_NT_SIGNATURE);
		
		TImgRaw nOptRaw = nFileRaw + nFstHdrLen;
		TU16 nOptSign = 0;
		RBSURE(ReadDatRaw(nOptRaw, &nOptSign, sizeof(nOptSign)));	
		if(nOptSign == WINPE_IMAGE_NT_OPTIONAL_HDR32_MAGIC)
		{
			RBSURE(ReadDatRaw(nOptRaw, &m_aImgNtHdr.X32.OptionalHeader, sizeof(m_aImgNtHdr.X32.OptionalHeader)));
			
			TImgOptHdr32& rImgOptHdr = m_aImgNtHdr.X32.OptionalHeader;
			m_dwEntryPoint	= rImgOptHdr.AddressOfEntryPoint;
			m_dwFileAlign	= rImgOptHdr.FileAlignment;
			m_dwSectAlign	= rImgOptHdr.SectionAlignment;
			m_bWow64Flage	= FALSE;
		}
		else if(nOptSign == WINPE_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
		{
			RBSURE(ReadDatRaw(nOptRaw, &m_aImgNtHdr.X64.OptionalHeader, sizeof(m_aImgNtHdr.X64.OptionalHeader)));

			TImgOptHdr64& rImgOptHdr = m_aImgNtHdr.X64.OptionalHeader;
			m_dwEntryPoint	= rImgOptHdr.AddressOfEntryPoint;
			m_dwFileAlign	= rImgOptHdr.FileAlignment;
			m_dwSectAlign	= rImgOptHdr.SectionAlignment;
			m_bWow64Flage	= TRUE;
		}
		else
		{
			return FALSE;
		}	
		return TRUE;
	}

	VOID ClearHeaders()
	{
		m_dwEntryPoint	= 0;
		m_dwFileAlign	= 0;
		m_dwSectAlign	= 0;
		m_bWow64Flage	= FALSE;
		
		DATA_CLEAN(m_aImgMzHdr);
		DATA_CLEAN(m_aImgNtHdr);
	}

	//////////////////////////////////////////////////////////////////////////
	BOOL ParseSections()
	{
		if( !DosHeader() ) return FALSE;
		//////////////////////////////////////////////////////////////////////////
		TU32 dwSecRaw = DosHeader()->e_lfanew 
			+ sizeof(TImgNtHdr32) 
			- sizeof(TImgOptHdr32)
			+ FileHeader()->SizeOfOptionalHeader;

		TU32 dwSecCnt = min(FileHeader()->NumberOfSections, WINPE_MAX_SECTION_COUNT);
		RBSURE(dwSecCnt);

		//////////////////////////////////////////////////////////////////////////
		TU32 dwImgHdrSize = 0;
		RBSURE(ImageHeaderSize(&dwImgHdrSize));
		m_dwMaxSectRaw = dwImgHdrSize;
		m_dwMaxSectRva = dwImgHdrSize;

		//////////////////////////////////////////////////////////////////////////
		m_aImgSecHdrLst.reserve(dwSecCnt);
		for(TU32 n = 0; n < dwSecCnt; n++)
		{
			TU32 dwSecHdrRaw = dwSecRaw + sizeof(TImgSecHdr)*n;

			TImgSecHdr aImgSecHdr;
			if(!ReadDatRaw(dwSecHdrRaw, &aImgSecHdr, sizeof(TImgSecHdr)))
				break;
			m_aImgSecHdrLst.push_back(aImgSecHdr);


			if(aImgSecHdr.SizeOfRawData > 0)
			{
				TU32 dwSecEndRaw\
					= aImgSecHdr.PointerToRawData 
					+ aImgSecHdr.SizeOfRawData;

				if(m_dwMaxSectRaw > dwSecEndRaw)
					m_dwMaxSectRaw = dwSecEndRaw;
			}

			if(aImgSecHdr.Misc.VirtualSize)
			{		
				TU32 dwSecEndRva\
					= aImgSecHdr.VirtualAddress 
					+ aImgSecHdr.Misc.VirtualSize;

				if(m_dwMaxSectRva > dwSecEndRva)
					m_dwMaxSectRva = dwSecEndRva;
			}

			TString sSecName;
			ReadStrRawA(dwSecHdrRaw, sSecName, 8);
			m_aImgSecNameLst.push_back(sSecName);
		}

		//////////////////////////////////////////////////////////////////////////
		{
			TSecMapItem aMapItm;
			aMapItm.dwSecIdx = ~0;
			aMapItm.dwBegRaw = 0;
			aMapItm.dwEndRaw = dwImgHdrSize;
			aMapItm.dwBegRva = 0;
			aMapItm.dwEndRva = dwImgHdrSize;
			m_aSecMapList.push_back(aMapItm);
		}
		
		TU32 dwRelCnt = m_aImgSecHdrLst.size();
		for(TU32 nSecIdx = 0; nSecIdx < dwRelCnt; nSecIdx++)
		{
			TImgSecHdr& rSecHdr = m_aImgSecHdrLst[nSecIdx];

			//if(!rSecHdr.SizeOfRawData)
			//	continue;

			if(!rSecHdr.Misc.VirtualSize)
				continue;

			TSecMapItem aMapItm;
			aMapItm.dwSecIdx = nSecIdx;
			aMapItm.dwBegRaw = rSecHdr.PointerToRawData;
			aMapItm.dwEndRaw = aMapItm.dwBegRaw + rSecHdr.SizeOfRawData;

			aMapItm.dwBegRva = rSecHdr.VirtualAddress;
			aMapItm.dwEndRva = aMapItm.dwBegRva + rSecHdr.Misc.VirtualSize;
			m_aSecMapList.push_back(aMapItm);
		}

		if(!m_aSecMapList.size())
			return FALSE;

		return TRUE;
	}	

	VOID ClearSections()
	{
		m_aImgSecHdrLst.clear();
		m_aImgSecNameLst.clear();
		m_aSecMapList.clear();
		m_dwMaxSectRva	= 0;
		m_dwMaxSectRaw	= 0;
	}

	//////////////////////////////////////////////////////////////////////////
	BOOL ParseImport()
	{
		TImgDatDir* lpImpDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_IMPORT);
		RBSURE(lpImpDatDir);
		RBSURE(IsValidRva(lpImpDatDir->VirtualAddress, lpImpDatDir->Size));

		TU32 dwImpEntCnt = lpImpDatDir->Size/sizeof(TImgImpDes);
		RBSURE(dwImpEntCnt > 1);

		TImgRaw dwDespRaw = 0;
		RBSURE(Rva2Raw(lpImpDatDir->VirtualAddress, sizeof(TImgImpDes), &dwDespRaw));

		for(TU32 n = 0; n < WINPE_MAX_IMPORT_COUNT; n++)
		{	
			//////////////////////////////////////////////////////////////////////////
			TImgImpDes aImpDes;
			if(!ReadDatRaw(dwDespRaw + sizeof(TImgImpDes)*n, &aImpDes, sizeof(TImgImpDes)))
				break;

			if(!aImpDes.Name || !aImpDes.OriginalFirstThunk || !aImpDes.FirstThunk)
				break;			

			//////////////////////////////////////////////////////////////////////////
			TString sModule;
			if(!ReadStrRvaA(aImpDes.Name, sModule))
				continue;

			m_aImgImpMap[sModule] = aImpDes;
			TFuncMap& rFuncMap = m_aImportMap[sModule];
			if(!ParseImportFuncMap(rFuncMap, aImpDes.OriginalFirstThunk, aImpDes.FirstThunk))
				break;
	
		}
		RBSURE(m_aImportMap.size());
		return TRUE;		
	}

	VOID ClearImport()
	{
		m_aImgImpMap.clear();
		m_aImportMap.clear();
	}

	BOOL ParseImportFuncMap(TFuncMap& rFuncMap, TImgRva dwThkTabRva, TImgRva dwAddrTabRva)
	{
		rFuncMap.clear();
		TImgRaw dwThkTabRaw = 0;
		RBSURE(Rva2Raw(dwThkTabRva, 1, &dwThkTabRaw));

		TU32 nAddEntLen = 0;
		TU32 nThkEntLen = 0;
		if(IsWow64())
		{
			nAddEntLen = sizeof(TU64);
			nThkEntLen = sizeof(TImgThkDat64);
		}
		else
		{
			nAddEntLen = sizeof(TU32);
			nThkEntLen = sizeof(TImgThkDat32);
		}

		for(TU32 dwImpIdx = 0; dwImpIdx < WINPE_MAX_FUNCTION_COUNT; dwImpIdx++)
		{
			TImgRva dwAddrRva = dwAddrTabRva + nAddEntLen*dwImpIdx;
			TImgRaw dwThunkRaw = dwThkTabRaw + nThkEntLen*dwImpIdx;

			TU16 wHint = 0;
			TString sFuncName;
			TU32 uNameRVA = 0;
			if(!ReadThunkDatRaw(dwThunkRaw, &wHint, sFuncName, uNameRVA))
				break;				

			TFuncEnt& rFuncEnt		= rFuncMap[sFuncName];
			rFuncEnt.TU32inal		= wHint;
			rFuncEnt.dwAddrRva		= dwAddrRva;
			rFuncEnt.nameRVA		= uNameRVA;
		}
		RBSURE(rFuncMap.size());
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	BOOL ParseExport()
	{
		TImgDatDir* lpExpDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_EXPORT);
		RBSURE(lpExpDatDir);
		RBSURE(IsValidRva(lpExpDatDir->VirtualAddress, lpExpDatDir->Size));
		RBSURE(ReadDatRva(lpExpDatDir->VirtualAddress, &m_aImgExpDir, sizeof(m_aImgExpDir)));
		RBSURE(ReadStrRvaA(m_aImgExpDir.Name, m_sExportModule));

		//////////////////////////////////////////////////////////////////////////
		TU32 TU32Base = m_aImgExpDir.Base;
		TU32 dwFuncCnt = min(m_aImgExpDir.NumberOfFunctions, WINPE_MAX_FUNCTION_COUNT);
		TU32 dwAddrTabRva = m_aImgExpDir.AddressOfFunctions;
		for(TU32 n = 0; n < dwFuncCnt; n++)
		{
			TU32 dwHint = TU32Base + n;
			TString sFuncName;
			FormatStr(sFuncName, "#%d", dwHint);

			TFuncEnt aFuncEnt;
			aFuncEnt.TU32inal = dwHint;
			aFuncEnt.dwAddrRva = dwAddrTabRva + n*sizeof(TImgRva);

			m_aExportMap[sFuncName] = aFuncEnt;
		}		

		//////////////////////////////////////////////////////////////////////////
		TU32 dwNameCnt = min(m_aImgExpDir.NumberOfNames, WINPE_MAX_FUNCTION_COUNT);		
		TU32 dwNameTabRva = m_aImgExpDir.AddressOfNames;
		RBSURE(dwNameCnt);

		TU32Vtr aNameTab(dwNameCnt);
		RBSURE(ReadDatRva(dwNameTabRva, &aNameTab[0], sizeof(TU32)*dwNameCnt));

		TU32 dwHintTabRva = m_aImgExpDir.AddressOfNameOrdinals;
		TU16Vtr aHintTab(dwNameCnt);
		RBSURE(ReadDatRva(dwNameTabRva, &aHintTab[0], sizeof(TU16)*dwNameCnt));

		for(TU32 n = 0; n < dwNameCnt; n++)
		{
			TString sFuncName;
			if(!ReadStrRvaA(aNameTab[n], sFuncName))
				continue;

			TFuncEnt aFuncEnt;
			aFuncEnt.TU32inal = aHintTab[n];
			aFuncEnt.dwAddrRva = dwAddrTabRva + n*sizeof(TImgRva);
			m_aExportMap[sFuncName] = aFuncEnt;

			TString sOrdName;
			FormatStr(sOrdName, "#%d", aHintTab[n]);
			m_aExportMap.erase(sOrdName);
		}
		return TRUE;
	}

	VOID ClearExport()
	{
		DATA_CLEAN(m_aImgExpDir);	
		m_sExportModule.clear();
		m_aExportMap.clear();		
	}
	//////////////////////////////////////////////////////////////////////////
	BOOL ParseResource()
	{		
		TImgDatDir* lpRsrcDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_RESOURCE);
		RBSURE(lpRsrcDatDir);
		RBSURE(IsValidRva(lpRsrcDatDir->VirtualAddress, lpRsrcDatDir->Size));

		TWinResLst* lpRootLst = ParseResourceDir(lpRsrcDatDir->VirtualAddress, 0, 0);
		RBSURE(lpRootLst);
		
		m_aRsrcRootEnt.SetSubList(lpRootLst);
		return TRUE;		
	}

	VOID ClearResource()
	{
		m_dwRrscDataCnt = 0;
		m_aRsrcNameLst.clear();
		m_aRsrcRootEnt.Clear();		
	}	
	TWinResLst* ParseResourceDir(TImgRva dwRootRva, TU32 dwDirOffs, TU32 dwLevel)
	{
		RVSURE(dwLevel < WINPE_MAX_RESOURCE_DEEP_LEVEL, NULL);

		TImgRaw dwDirRaw = 0;
		RVSURE(Rva2Raw(dwRootRva + dwDirOffs, sizeof(TImgResDir), &dwDirRaw), NULL);

		TImgResDir aImgRsrcDir;
		RVSURE(ReadDatRaw(dwDirRaw, &aImgRsrcDir, sizeof(aImgRsrcDir)), NULL);

		TU32 dwEntCnt = aImgRsrcDir.NumberOfIdEntries + aImgRsrcDir.NumberOfNamedEntries;
		dwEntCnt = min(dwEntCnt, WINPE_MAX_RESOURCE_ENTRY_COUNT);
		RVSURE(dwEntCnt > 0, NULL);

		typedef std::auto_ptr<TWinResLst> TRestLstPtr;
		TRestLstPtr aResLstPtr(TWinResLst::Alloc(dwEntCnt));
		memcpy(aResLstPtr->Header(), &aImgRsrcDir, sizeof(aImgRsrcDir));

		TU32 nNameCnt = 0, nIdCnt = 0;
		TImgRaw dwEntRaw = dwDirRaw + sizeof(TImgResDir);
		for(TU32 n = 0; n < dwEntCnt; n++)
		{
			TWinResLst::TEntry* lpEntry = aResLstPtr->Entry(n);	

			TImgResEnt aImgRsrcEnt;
			if(!ReadDatRaw(dwEntRaw + sizeof(TImgResEnt) * n, &aImgRsrcEnt, sizeof(aImgRsrcEnt)), NULL)
				break;

			if(aImgRsrcEnt.NameIsString)
			{
				TString sKeyName;	
				if(!ReadRsrcStrRvaU(dwRootRva + aImgRsrcEnt.NameOffset, sKeyName))
					continue;	

				m_aRsrcNameLst.push_back(sKeyName);

				LPCSTR szName = m_aRsrcNameLst.back().c_str();
				lpEntry->SetNameStr(szName);
				nNameCnt++;
			}
			else
			{
				lpEntry->SetNameId(aImgRsrcEnt.Id);
				nIdCnt++;
			}

			if(aImgRsrcEnt.DataIsDirectory)
			{
				TWinResLst* lpSubList = ParseResourceDir(dwRootRva, aImgRsrcEnt.OffsetToDirectory, dwLevel + 1);
				if(!lpSubList)
					continue;

				lpEntry->SetSubList(lpSubList);
			}
			else
			{
				TWinResDat* lpSubData = ParseResourceDat(dwRootRva, aImgRsrcEnt.OffsetToData);
				if(!lpSubData)
					continue;

				lpEntry->SetSubData(lpSubData);
			}
		}
		RVSURE(aResLstPtr->Rebuild(nIdCnt, nNameCnt), NULL);
		return aResLstPtr.release();
	}

	TWinResDat* ParseResourceDat(TImgRva dwRootRva, TU32 dwDatOffs)
	{	
		std::auto_ptr<TWinResDat> aResDatPtr(new TWinResDat);

		TImgRva nResRva = dwRootRva + dwDatOffs;
		TImgResDat* lpResDat = aResDatPtr->Header();
		RVSURE(ReadDatRva(nResRva, lpResDat, sizeof(TImgResDat)), NULL);
		RVSURE(lpResDat->Size && lpResDat->OffsetToData > 0, NULL);
		RVSURE(lpResDat->Size < WINPE_MAX_RESOURCE_DATA_SIZE, NULL);		

		aResDatPtr->DatRva = lpResDat->OffsetToData;
		aResDatPtr->DatLen = lpResDat->Size;
		m_dwRrscDataCnt++;
		return aResDatPtr.release();
	}

	TWinResEnt* ResourceEntry(LPCSTR szType = NULL, LPCSTR szNameId = NULL, LPCSTR szLang = NULL)
	{
		TWinResEnt* lpEntry = ResourceRootEntry();
		RVSURE(lpEntry, NULL);
		if(szType)
		{
			lpEntry = lpEntry->SubFind(szType);
			RVSURE(lpEntry, NULL);

			if(szNameId)
			{
				lpEntry = lpEntry->SubFind(szNameId);
				RVSURE(lpEntry, NULL);

				if(szLang)
				{
					lpEntry = lpEntry->SubFind(szLang);
					RVSURE(lpEntry, NULL);
				}	
			}
		}
		return lpEntry;
	}

	TWinResEnt* ResourceRootEntry()
	{
		RVSURE(ParseLevel(PPL_IMAGE_RESOURCE), NULL);
		RVSURE(m_aRsrcRootEnt.lpData, NULL);	
		TWinResEnt* lpEntry = &m_aRsrcRootEnt;
		return lpEntry;
	}
	TWinResEnt* ResourceTypeEntry(LPCSTR szType)
	{
		TWinResEnt* lpEntry = ResourceRootEntry();
		RVSURE(lpEntry, NULL);

		lpEntry = lpEntry->SubFind(szType);
		return lpEntry;
	}

	TWinResEnt* ResourceNameIdEntry(LPCSTR szType, LPCSTR szNameId)
	{		
		TWinResEnt* lpEntry = ResourceTypeEntry(szType);
		RVSURE(lpEntry, NULL);

		lpEntry = lpEntry->SubFind(szNameId);		
		return lpEntry;
	}

	TWinResEnt* ResourceLanguageEntry(LPCSTR szType, LPCSTR szNameId, LPCSTR szLang)
	{		
		TWinResEnt* lpEntry = ResourceNameIdEntry(szType, szNameId);
		RVSURE(lpEntry, NULL);

		lpEntry = lpEntry->SubFind(szLang);
		return lpEntry;
	}


	//////////////////////////////////////////////////////////////////////////
	BOOL ParseRelocation()
	{		
		//////////////////////////////////////////////////////////////////////////
		TImgDatDir* lpRelDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_BASERELOC);
		RBSURE(lpRelDatDir);
		RBSURE(IsValidRva(lpRelDatDir->VirtualAddress ,lpRelDatDir->Size));

		TU32 dwBlkCurRva = lpRelDatDir->VirtualAddress;
		RBSURE(dwBlkCurRva);

		TU32 dwBlkEndRva = dwBlkCurRva + lpRelDatDir->Size;
		while(dwBlkCurRva < dwBlkEndRva)
		{
			TU32 dwBlkLen = 0;
			if(!ParseRelocBlock(dwBlkCurRva, &dwBlkLen))
				break;

			if(!dwBlkLen)
				break;

			dwBlkCurRva += dwBlkLen;
		};
		return TRUE;		
	}

	VOID ClearRelocation()
	{
		m_aRelocMap.clear();
	}
	BOOL ParseRelocBlock(TImgRva dwRva, TU32* lpBlkSize = NULL)
	{
		TImgBasRel aImgBasRel;
		RBSURE(ReadDatRva(dwRva, &aImgBasRel, sizeof(aImgBasRel)));
		RBSURE(aImgBasRel.SizeOfBlock && aImgBasRel.VirtualAddress);

		TU32 dwBlkSize = aImgBasRel.SizeOfBlock;
		RBSURE(dwBlkSize < WINPE_MAX_RELOCATION_BLOCK_SIZE);
		TU32 dwTailSize = sizeof(TImgBasRel) + sizeof(TU16);
		RBSURE(dwBlkSize > dwTailSize);

		TU32 dwEntCnt = (dwBlkSize - dwTailSize) / sizeof(TU16);
		RBSURE(dwEntCnt);

		TU32 dwBlkRva = aImgBasRel.VirtualAddress;
		TRelocBlock& rRelBlk = m_aRelocMap[dwBlkRva];

		rRelBlk.resize(dwEntCnt);
		RBSURE(ReadDatRva(dwRva, &rRelBlk[0], sizeof(TU16)*dwEntCnt));
		ADDR_ASSIGN(lpBlkSize, dwBlkSize);
		return TRUE;
	}

	//////////////////////////////////////////////////////////////////////////
	BOOL ParseTls()
	{
		if(IsWow64())
			return ParseTls64();
		else
			return ParseTls32();
	}

	BOOL ParseTls32()
	{
		TImgDatDir* lpTlsDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_TLS);
		RBSURE(lpTlsDatDir);
		RBSURE(IsValidRva(lpTlsDatDir->VirtualAddress, lpTlsDatDir->Size));

		TU64 qwTlsCbTabVa = 0;
		RBSURE(ReadDatRva(lpTlsDatDir->VirtualAddress, &m_aImgTlsDir.X32, sizeof(m_aImgTlsDir.X32)));
		qwTlsCbTabVa = m_aImgTlsDir.X32.AddressOfCallBacks;
			
		TImgRva dwTlsCbTabRva;
		RBSURE(Va2Rva(qwTlsCbTabVa, 1, &dwTlsCbTabRva));

		TImgRaw dwTlsCbTabRaw;
		RBSURE(Rva2Raw(dwTlsCbTabRva,1, &dwTlsCbTabRaw));

		m_aTlsFuncLst.clear();		
		for(TU32 n = 0; n < WINPE_MAX_TLS_CALLBACK_COUNT; n++)
		{
			TU32 dwFuncVa = 0;
			if(!ReadDatRaw(dwTlsCbTabRaw, &dwFuncVa, sizeof(dwFuncVa)))
				break;

			if(!dwFuncVa)
				break;

			TImgRva dwFuncRva = 0;
			if(!Va2Rva(dwFuncVa, 1, &dwFuncRva))
				break;

			m_aTlsFuncLst.push_back(dwFuncRva);
			dwTlsCbTabRaw += sizeof(TU32);
		}
		return TRUE;
	}

	BOOL ParseTls64()
	{
		TImgDatDir* lpTlsDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_TLS);
		RBSURE(lpTlsDatDir);
		RBSURE(IsValidRva(lpTlsDatDir->VirtualAddress, lpTlsDatDir->Size));

		TU64 qwTlsCbTabVa = 0;	
		RBSURE(ReadDatRva(lpTlsDatDir->VirtualAddress, &m_aImgTlsDir.X64, sizeof(m_aImgTlsDir.X64)));
		qwTlsCbTabVa = m_aImgTlsDir.X64.AddressOfCallBacks;			

		TImgRva dwTlsCbTabRva;
		RBSURE(Va2Rva(qwTlsCbTabVa, 1, &dwTlsCbTabRva));

		TImgRaw dwTlsCbTabRaw;
		RBSURE(Rva2Raw(dwTlsCbTabRva,1, &dwTlsCbTabRaw));

		m_aTlsFuncLst.clear();	
		for(TU32 n = 0; n < WINPE_MAX_TLS_CALLBACK_COUNT; n++)
		{
			TU64 qwFuncVa = 0;
			if(!ReadDatRaw(dwTlsCbTabRaw, &qwFuncVa, sizeof(qwFuncVa)))
				break;

			if(!qwFuncVa)
				break;

			TImgRva dwFuncRva = 0;
			if(!Va2Rva(qwFuncVa, 1, &dwFuncRva))
				break;

			m_aTlsFuncLst.push_back(dwFuncRva);
			dwTlsCbTabRaw += sizeof(TU64);
		}
		
		return TRUE;
	}

	VOID ClearTls()
	{
		DATA_CLEAN(m_aImgTlsDir);
		m_aTlsFuncLst.clear();
	}
	//////////////////////////////////////////////////////////////////////////
	BOOL ParseDebug()
	{
		TImgDatDir* lpDbgDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_DEBUG);
		RBSURE(lpDbgDatDir);
		RBSURE(IsValidRva(lpDbgDatDir->VirtualAddress, lpDbgDatDir->Size));
		RBSURE(ReadDatRva(lpDbgDatDir->VirtualAddress, &m_aImgDbgDir, sizeof(m_aImgDbgDir)));

		TU32 dwDataRaw = m_aImgDbgDir.PointerToRawData;
		TU32 dwDataLen = m_aImgDbgDir.SizeOfData;	
		RBSURE(dwDataRaw && dwDataLen);

		switch(m_aImgDbgDir.Type)
		{
		case IMAGE_DEBUG_TYPE_CODEVIEW:
			return ParseDebugCodeView(dwDataRaw, dwDataLen);

		case IMAGE_DEBUG_TYPE_MISC:
			return ParseDebugMisc(dwDataRaw, dwDataLen);
		}

		return FALSE;
	}	

	VOID ClearDebug()
	{
		DATA_CLEAN(m_aImgDbgDir);
		m_sDebugFilePath.clear();
	}
	BOOL ParseDebugCodeView(TImgRaw dwRaw, TImgSize dwSize)
	{
		TU32 dwMagic = 0;
		RBSURE(ReadDatRaw(dwRaw, &dwMagic, sizeof(dwMagic)));

		if(dwMagic == CV_INFO_PDB20_SIGNATURE)
		{
			CV_INFO_PDB20 aPdbInfo;
			RBSURE(ReadDatRaw(dwRaw, &aPdbInfo, sizeof(aPdbInfo)));
			RBSURE(ReadStrRawA(dwRaw+sizeof(aPdbInfo), m_sDebugFilePath));
			return TRUE;			
		}
		else if(dwMagic == CV_INFO_PDB70_SIGNATURE)
		{
			CV_INFO_PDB70 aPdbInfo;
			RBSURE(ReadDatRaw(dwRaw, &aPdbInfo, sizeof(aPdbInfo)));
			RBSURE(ReadStrRawA(dwRaw+sizeof(aPdbInfo), m_sDebugFilePath));
			return TRUE;
		}
		return FALSE;
	}

	BOOL ParseDebugMisc(TImgRaw dwRaw, TImgSize dwSize)
	{
		return FALSE;
	}

	//////////////////////////////////////////////////////////////////////////
	BOOL ParseDelayImport()
	{
		TImgDatDir* lpDlyImpDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
		RBSURE(lpDlyImpDir);
		RBSURE(IsValidRva(lpDlyImpDir->VirtualAddress, lpDlyImpDir->Size));

		TU32 dwEntCount = lpDlyImpDir->Size/sizeof(TImgDlyDes);
		RBSURE(dwEntCount > 1);

		TImgRaw dwDesBegRaw = 0;
		RBSURE(Rva2Raw(lpDlyImpDir->VirtualAddress, lpDlyImpDir->Size, &dwDesBegRaw));

		//////////////////////////////////////////////////////////////////////////
		for(TU32 nIdx = 0; nIdx < WINPE_MAX_IMPORT_COUNT; nIdx++)
		{						
			TImgDlyDes aImgDlyDir;
			TImgRaw dwEntRaw = dwDesBegRaw + sizeof(aImgDlyDir) * nIdx;
			if(!ReadDatRaw(dwEntRaw, &aImgDlyDir, sizeof(aImgDlyDir)))
				break;

			if(!aImgDlyDir.Name || !aImgDlyDir.AddressTable || !aImgDlyDir.NameThunk)
				break;

			//////////////////////////////////////////////////////////////////////////
			TString sModule;
			if(!ReadStrRvaA(aImgDlyDir.Name, sModule))
				continue;

			m_aImgDlyMap[sModule] = aImgDlyDir;
			TFuncMap& rFuncMap = m_aDlyFucMap[sModule];
			if(!ParseImportFuncMap(rFuncMap, aImgDlyDir.NameThunk, aImgDlyDir.AddressTable))
				break;				
		}		
		return TRUE;
	}

	VOID ClearDelayImport()
	{
		m_aImgDlyMap.clear();  
		m_aDlyFucMap.clear();   
	}
	//////////////////////////////////////////////////////////////////////////
	BOOL ParseLoadConfig()
	{
		TImgDatDir* lpCfgDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG);
		RBSURE(lpCfgDatDir);

		TImgRva		aDirRva = lpCfgDatDir->VirtualAddress;
		TImgSize	aDirLen = lpCfgDatDir->Size;
		RBSURE(IsValidRva(aDirRva, aDirLen));

		TU32		dwHdlEntCnt = 0;
		TImgRva		aHdlTabRva  = 0;
		if(IsWow64())
		{
			RBSURE(ReadDatRva(aDirRva, &m_aImgCfgDir.X64, sizeof(m_aImgCfgDir.X64)));
			dwHdlEntCnt = (TU32)(m_aImgCfgDir.X64.SEHandlerCount);
			RBSURE(Va2Rva(m_aImgCfgDir.X64.SEHandlerTable, sizeof(TImgRva), &aHdlTabRva));
		}
		else
		{
			RBSURE(ReadDatRva(aDirRva, &m_aImgCfgDir.X32, sizeof(m_aImgCfgDir.X32)));
			dwHdlEntCnt = (TU32)(m_aImgCfgDir.X32.SEHandlerCount);
			RBSURE(Va2Rva(m_aImgCfgDir.X32.SEHandlerTable, sizeof(TImgRva), &aHdlTabRva));
		}		

		if(dwHdlEntCnt > 0)
		{
			dwHdlEntCnt = min(dwHdlEntCnt, WINPE_MAX_FUNCTION_COUNT);
			m_aImgSehHdlLst.resize(dwHdlEntCnt, 0);
			if(!ReadDatRva(aHdlTabRva, &m_aImgSehHdlLst[0], dwHdlEntCnt*sizeof(TImgRva)))
				m_aImgSehHdlLst.clear();
		}	
		return TRUE;
	}
	VOID ClearLoadConfig()
	{
		DATA_CLEAN(m_aImgCfgDir);
		m_aImgSehHdlLst.clear();
	}
	//////////////////////////////////////////////////////////////////////////
	BOOL ParseCertificate()
	{
		TImgDatDir* lpCrtDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_SECURITY);
		RBSURE(lpCrtDatDir);
		RBSURE(IsValidRaw(lpCrtDatDir->VirtualAddress, lpCrtDatDir->Size));

		TImgRaw dwCertRaw = lpCrtDatDir->VirtualAddress;
		RBSURE(ReadDatRaw(dwCertRaw, &m_aWinCertHdr, sizeof(m_aWinCertHdr)));

		m_dwCertRaw = dwCertRaw + sizeof(m_aWinCertHdr);
		m_dwCertLen = m_aWinCertHdr.dwLength - sizeof(m_aWinCertHdr);
		return TRUE;
	}
	VOID ClearCertificate()
	{
		DATA_CLEAN(m_aWinCertHdr);       
		m_dwCertRaw = 0;         
		m_dwCertLen = 0;	     
	}	

	//////////////////////////////////////////////////////////////////////////
	BOOL ParseBoundImport()
	{
		//////////////////////////////////////////////////////////////////////////
		TImgDatDir* lpBndDatDir = DataDirectory(IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT);
		RBSURE(lpBndDatDir);

		TImgRva dwDirRva = lpBndDatDir->VirtualAddress;
		TU32	dwDirLen = lpBndDatDir->Size;
		RBSURE(IsValidRva(dwDirRva, dwDirLen));		

		TU32 dwBndCnt = dwDirLen/sizeof(TImgBndDes);
		RBSURE(dwBndCnt > 1 && dwBndCnt < WINPE_MAX_IMPORT_COUNT);	

		TImgRaw dwDirRaw = 0;
		RBSURE(Rva2Raw(dwDirRva, sizeof(TImgBndDes), &dwDirRaw));
		
		m_aImgBndDesLst.resize(dwBndCnt);
		RBSURE(ReadDatRaw(dwDirRaw, &m_aImgBndDesLst[0], sizeof(TImgBndDes)*dwBndCnt));

		//////////////////////////////////////////////////////////////////////////
		TU32 dwBndEntCnt = 0, dwBndModCnt = 0, dwBndFwdCnt = 0;
		for(TU32 nIdx = 0; nIdx < dwBndCnt; nIdx++)
		{			
			TImgBndDes& rImgBndDes = m_aImgBndDesLst[nIdx];
			if(!rImgBndDes.TimeDateStamp && !rImgBndDes.OffsetModuleName)
				break;

			TString sModule;
			TImgRaw dwStrRaw = dwDirRaw + rImgBndDes.OffsetModuleName;
			if(!ReadStrRawA(dwStrRaw, sModule))
				break;

			if(dwBndFwdCnt == 0)
			{
				dwBndFwdCnt = rImgBndDes.NumberOfModuleForwarderRefs;
				m_aBndModNameMap[sModule] = &rImgBndDes;
			}
			else
			{
				m_aBndFwdNameMap[rImgBndDes.OffsetModuleName] = sModule;
				dwBndFwdCnt--;
			}
		}
		RBSURE(dwBndEntCnt > 0);
		return TRUE;
	}
	VOID ClearBoundImport()
	{
		m_aImgBndDesLst.clear();   
		m_aBndModNameMap.clear();  
		m_aBndFwdNameMap.clear();  
	}
	//////////////////////////////////////////////////////////////////////////
	BOOL ParseClrRuntime()
	{
		//////////////////////////////////////////////////////////////////////////
		TImgDatDir* lpClrDatDir = DataDirectory(WINPE_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR);
		RBSURE(lpClrDatDir);

		TImgRva dwDirRva = lpClrDatDir->VirtualAddress;
		TU32	dwDirLen = lpClrDatDir->Size;
		RBSURE(IsValidRva(dwDirRva, dwDirLen));	
		RBSURE(dwDirLen >= sizeof(m_aImgClrHdr));
		RBSURE(ReadDatRva(dwDirRva, &m_aImgClrHdr, sizeof(m_aImgClrHdr)));

		return TRUE; 
	}
	VOID ClearClrRuntime()
	{
		DATA_CLEAN(m_aImgClrHdr);
	}
};//CWinPeParser

};//WinPe


#endif